1 /* vim:expandtab:ts=2 sw=2:
2 */
3 /*  Grafx2 - The Ultimate 256-color bitmap paint program
4 
5 	Copyright owned by various GrafX2 authors, see COPYRIGHT.txt for details.
6 
7     Grafx2 is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License
9     as published by the Free Software Foundation; version 2
10     of the License.
11 
12     Grafx2 is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with Grafx2; if not, see <http://www.gnu.org/licenses/>
19 */
20 
21 // Pour désactiver le support TrueType, définir NOTTF
22 // To disable TrueType support, define NOTTF
23 
24 #include <string.h>
25 #include <stdlib.h>
26 #include <ctype.h> // tolower()
27 
28 // TrueType
29 #ifndef NOTTF
30 #include <SDL_ttf.h>
31 
32 #if defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__)
33 // No fontconfig
34 #elif defined(USE_FC) && !defined(NOTTF)
35   #include <fontconfig/fontconfig.h>
36 #endif
37 #endif
38 
39 #if defined(__macosx__)
40   #import <CoreFoundation/CoreFoundation.h>
41   #import <sys/param.h>
42 #endif
43 
44 #ifdef _MSC_VER
45 #include <stdio.h>
46 #define strdup _strdup
47 #if _MSC_VER < 1900
48 #define snprintf _snprintf
49 #endif
50 #endif
51 #if defined(WIN32)
52 #include <windows.h>
53 #include <malloc.h>
54 #endif
55 
56 #if defined(USE_SDL) || defined(USE_SDL2)
57 #include <SDL_image.h>
58 #include "sdlscreen.h"
59 #endif
60 
61 #include "struct.h"
62 #include "global.h"
63 #include "io.h"
64 #include "errors.h"
65 #include "windows.h"
66 #include "misc.h"
67 #include "setup.h"
68 #include "loadsave.h"
69 #include "SFont.h"
70 
71 /**
72  * Element of the font linked list
73  */
74 typedef struct T_Font
75 {
76   char * Name;
77   int    Is_truetype;
78   int    Is_bitmap;
79   char   Label[22];
80 
81   // Liste chainée simple
82   struct T_Font * Next;
83   struct T_Font * Previous;
84 } T_Font;
85 
86 /**
87  * Head of the font linked list
88  */
89 T_Font * font_list_start;
90 
91 // Inspiré par Allegro
92 #define EXTID(a,b,c) ((((a)&255)<<16) | (((b)&255)<<8) | (((c)&255)))
93 #define EXTID4(a,b,c,d) ((((a)&255)<<24) | (((b)&255)<<16) | (((c)&255)<<8) | (((d)&255)))
94 
Compare_fonts(T_Font * font_1,T_Font * font_2)95 static int Compare_fonts(T_Font * font_1, T_Font * font_2)
96 {
97   if (font_1->Is_bitmap && !font_2->Is_bitmap)
98     return -1;
99   if (font_2->Is_bitmap && !font_1->Is_bitmap)
100     return 1;
101   return strcmp(font_1->Label, font_2->Label);
102 }
103 
Insert_font(T_Font * font)104 static void Insert_font(T_Font * font)
105 {
106   // Gestion Liste
107   font->Next = NULL;
108   font->Previous = NULL;
109   if (font_list_start==NULL)
110   {
111     // Premiere (liste vide)
112     font_list_start = font;
113   }
114   else
115   {
116     int compare;
117     compare = Compare_fonts(font, font_list_start);
118     if (compare<=0)
119     {
120       if (compare==0 && !strcmp(font->Name, font_list_start->Name))
121       {
122         // Doublon
123         free(font->Name);
124         free(font);
125         return;
126       }
127       // Avant la premiere
128       font->Next=font_list_start;
129       font_list_start=font;
130     }
131     else
132     {
133       T_Font *searched_font;
134       searched_font=font_list_start;
135       while (searched_font->Next && (compare=Compare_fonts(font, searched_font->Next))>0)
136         searched_font=searched_font->Next;
137       // Après searched_font
138       if (compare==0 && strcmp(font->Name, searched_font->Next->Name)==0)
139       {
140         // Doublon
141         free(font->Name);
142         free(font);
143         return;
144       }
145       font->Next=searched_font->Next;
146       searched_font->Next=font;
147     }
148   }
149 }
150 
151 // Ajout d'une fonte à la liste.
Add_font(const char * name,const char * font_name)152 static void Add_font(const char *name, const char * font_name)
153 {
154   T_Font * font;
155   int size=strlen(name)+1;
156   int index;
157 
158   // Détermination du type:
159 
160 #if defined(__macosx__)
161   char strFontName[512];
162   CFStringRef CFSFontName;// = CFSTR(name);
163 
164   if (size < 6) return;
165 
166   CFSFontName = CFStringCreateWithBytes(NULL, (UInt8 *) name, size - 1, kCFStringEncodingASCII, false);
167   // Fix some funny names
168   CFStringGetCString(CFSFontName, strFontName, 512, kCFStringEncodingASCII);
169 
170   // Now we have a printable font name, use it
171   name = strFontName;
172 
173 #else
174   if (size<5 ||
175       name[size-5]!='.')
176     return;
177 #endif
178 
179 #if defined(WIN32) && defined(NOTTF)
180   // Register font in windows so they will be visible with EnumFontFamiliesEx()
181   if (AddFontResourceExA(name, FR_PRIVATE, 0) > 0)
182     return;
183 #endif
184 
185   font = (T_Font *)malloc(sizeof(T_Font));
186 
187   switch (EXTID(tolower(name[size-4]), tolower(name[size-3]), tolower(name[size-2])))
188   {
189     case EXTID('t','t','f'):
190     case EXTID('f','o','n'):
191     case EXTID('o','t','f'):
192     case EXTID('p','f','b'):
193       font->Is_truetype = 1;
194       font->Is_bitmap = 0;
195       break;
196     case EXTID('b','m','p'):
197     case EXTID('g','i','f'):
198     case EXTID('j','p','g'):
199     case EXTID('l','b','m'):
200     case EXTID('p','c','x'):
201     case EXTID('p','n','g'):
202     case EXTID('t','g','a'):
203     case EXTID('t','i','f'):
204     case EXTID('x','c','f'):
205     case EXTID('x','p','m'):
206     case EXTID('.','x','v'):
207       font->Is_truetype = 0;
208       font->Is_bitmap = 1;
209       break;
210     default:
211       #if defined(__macosx__)
212          if(strcasecmp(&name[size-6], "dfont") == 0)
213          {
214            font->Is_truetype = 1;
215            font->Is_bitmap = 0;
216          }
217          else
218          {
219             free(font);
220             return;
221          }
222       #else
223          free(font);
224          return;
225       #endif
226   }
227 
228   font->Name = strdup(name);
229   // Label
230   memset(font->Label, ' ', sizeof(font->Label));
231   font->Label[19] = '\0';
232   if (font->Is_truetype)
233     font->Label[17]=font->Label[18]='T'; // Logo TT
234   for (index=0; index < 17 && font_name[index]!='\0' && font_name[index]!='.'; index++)
235     font->Label[index]=font_name[index];
236 
237   Insert_font(font);
238 }
239 
240 
241 // Trouve le nom d'une fonte par son numéro
Font_name(int index)242 const char * Font_name(int index)
243 {
244   T_Font *font = font_list_start;
245   if (index < 0 || font == NULL)
246     return "";
247   while (index--)
248   {
249     font = font->Next;
250     if (font == NULL)
251       return "";
252   }
253   return font->Name;
254 }
255 
256 
257 // Trouve le libellé d'affichage d'une fonte par son numéro
258 // Renvoie un pointeur sur un buffer statique de 20 caracteres.
Font_label(int index)259 const char * Font_label(int index)
260 {
261   T_Font *font = font_list_start;
262 
263   font = font_list_start;
264   if (index < 0 || font == NULL)
265     return "                   ";
266   while (index--)
267   {
268     font = font->Next;
269     if (font == NULL)
270       return "                   ";
271   }
272   return font->Label;
273 }
274 
275 
276 // Vérifie si une fonte donnée est TrueType
TrueType_font(int index)277 int TrueType_font(int index)
278 {
279   T_Font *font = font_list_start;
280   if (index < 0 || font == NULL)
281     return 0;
282   while (index--)
283   {
284     font = font->Next;
285     if (font == NULL)
286       return 0;
287   }
288   return font->Is_truetype;
289 }
290 
Font_count(void)291 int Font_count(void)
292 {
293   T_Font *font = font_list_start;
294   int count = 0;
295 
296   while (font != NULL)
297   {
298     count++;
299     font = font->Next;
300   }
301   return count;
302 }
303 
304 #if defined(WIN32) && defined(NOTTF)
EnumFontFamCallback(CONST LOGFONTA * lpelf,CONST TEXTMETRICA * lpntm,DWORD FontType,LPARAM lParam)305 static int CALLBACK EnumFontFamCallback(CONST LOGFONTA *lpelf, CONST TEXTMETRICA *lpntm, DWORD FontType, LPARAM lParam)
306 {
307   char type[3] = { ' ', ' ', '\0' };
308   T_Font * font;
309 
310   (void)lParam; // we don't use the custom callback param
311   if (FontType & TRUETYPE_FONTTYPE)
312     type[0] = type[1] = 'T';
313   else if (FontType & RASTER_FONTTYPE)
314     type[0] = 'R';  // Raster font.
315   if (((CONST NEWTEXTMETRICA *)lpntm)->ntmFlags & NTM_TT_OPENTYPE)
316     type[0] = 'O';  // OpenType font
317   font = (T_Font *)malloc(sizeof(T_Font));
318   font->Is_bitmap = 0;
319   font->Is_truetype = 1;
320   snprintf(font->Label, sizeof(font->Label), "%-17.17s%s", lpelf->lfFaceName, type);
321   font->Name = strdup(lpelf->lfFaceName);
322 
323   Insert_font(font);
324   return 1; // non-zero : continue enumeration
325 }
326 #endif
327 
328 
329 // Initialisation à faire une fois au début du programme
Init_text(void)330 void Init_text(void)
331 {
332   char * directory_name;
333   #ifndef NOTTF
334   // Initialisation de TTF
335   TTF_Init();
336   #endif
337 
338   // Initialisation des fontes
339   font_list_start = NULL;
340   // Parcours du répertoire "fonts"
341   directory_name = Filepath_append_to_dir(Data_directory, FONTS_SUBDIRECTORY);
342   For_each_file(directory_name, Add_font);
343   free(directory_name);
344   // fonts subdirectory in Config_directory
345   directory_name = Filepath_append_to_dir(Config_directory, "fonts");
346   For_each_file(directory_name, Add_font);
347   free(directory_name);
348 
349   #if defined(WIN32)
350     // Parcours du répertoire systeme windows "fonts"
351     #ifndef NOTTF
352     {
353       char * WindowsPath = getenv("windir");
354       if (WindowsPath)
355       {
356         directory_name = Filepath_append_to_dir(WindowsPath, "FONTS");
357         For_each_file(directory_name, Add_font);
358         free(directory_name);
359       }
360     }
361     #else
362     {
363       LOGFONTA lf;
364       HDC dc = GetDC(NULL);
365       memset(&lf, 0, sizeof(lf));
366       lf.lfCharSet = ANSI_CHARSET /* DEFAULT_CHARSET*/;
367       lf.lfPitchAndFamily = 0;
368       //EnumFontsA(dc, NULL, EnumFontCallback, NULL);
369       //EnumFontFamiliesA(dc, NULL, EnumFontFamCallback, 0);
370       EnumFontFamiliesExA(dc, &lf, EnumFontFamCallback, 0, 0);
371       ReleaseDC(NULL, dc);
372     }
373     #endif
374   #elif defined(__macosx__)
375     // Récupération de la liste des fonts avec fontconfig
376     #ifndef NOTTF
377     {
378 
379       int i,number;
380       char * home_dir = NULL;
381       const char *font_path_list[3] = {
382          "/System/Library/Fonts",
383          "/Library/Fonts"
384       };
385       number = 2;
386       // Make sure we also search into the user's fonts directory
387       //CFURLRef url = (CFURLRef) CFCopyHomeDirectoryURLForUser(NULL);
388       //CFURLGetFileSystemRepresentation(url, true, (UInt8 *) home_dir, MAXPATHLEN);
389       if (getenv("HOME") != NULL)
390       {
391         home_dir = Filepath_append_to_dir(getenv("HOME"), "Library/Fonts");
392         font_path_list[number++] = home_dir;
393       }
394 
395       for(i=0;i<number;i++)
396          For_each_file(font_path_list[i],Add_font);
397 
398       free(home_dir);
399       //CFRelease(url);
400     }
401     #endif
402 
403   #elif defined(__CAANOO__) || defined(__WIZ__) || defined(__GP2X__)
404   // No fontconfig : Only use fonts from Grafx2
405   #elif defined(USE_FC)
406     #ifndef NOTTF
407        {
408 	FcStrList* dirs;
409         FcChar8 * fdir;
410 	dirs = FcConfigGetFontDirs(NULL);
411 	fdir = FcStrListNext(dirs);
412         while(fdir != NULL)
413 	{
414             For_each_file((char *)fdir,Add_font);
415 	    fdir = FcStrListNext(dirs);
416 	}
417 
418         FcStrListDone(dirs);
419        }
420     #endif
421   #elif defined(__amigaos4__) || defined(__amigaos__)
422     #ifndef NOTTF
423       For_each_file( "FONTS:_TrueType", Add_font );
424     #endif
425   #elif defined(__AROS__)
426     #ifndef NOTTF
427       For_each_file( "FONTS:TrueType", Add_font );
428     #endif
429   #elif defined(__BEOS__)
430     #ifndef NOTTF
431       For_each_file("/etc/fonts/ttfonts", Add_font);
432     #endif
433   #elif defined(__HAIKU__)
434     #ifndef NOTTF
435       For_each_file("/boot/system/data/fonts/ttfonts/", Add_font);
436     #endif
437   #elif defined(__SKYOS__)
438     #ifndef NOTTF
439       For_each_file("/boot/system/fonts", Add_font);
440     #endif
441   #elif defined(__MINT__)
442     #ifndef NOTTF
443       For_each_file("C:/BTFONTS", Add_font);
444     #endif
445 
446   #endif
447 }
448 
449 // Informe si texte.c a été compilé avec l'option de support TrueType ou pas.
TrueType_is_supported()450 int TrueType_is_supported()
451 {
452   #if !defined(NOTTF) || defined(WIN32)
453   return 1;
454   #else
455   return 0;
456   #endif
457 }
458 
Uninit_text(void)459 void Uninit_text(void)
460 {
461 #ifndef NOTTF
462   TTF_Quit();
463 #if defined(USE_FC)
464   FcFini();
465 #endif
466 #endif
467   while (font_list_start != NULL)
468   {
469     T_Font * font = font_list_start->Next;
470     free(font_list_start->Name);
471     free(font_list_start);
472     font_list_start = font;
473   }
474 }
475 
476 #ifndef NOTTF
Render_text_TTF(const char * str,int font_number,int size,int antialias,int bold,int italic,int * width,int * height,T_Palette palette)477 byte *Render_text_TTF(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette)
478 {
479   TTF_Font *font;
480   SDL_Surface * text_surface;
481   byte * new_brush;
482   int style;
483 
484   SDL_Color fg_color;
485   SDL_Color bg_color;
486 
487   // Chargement de la fonte
488   font=TTF_OpenFont(Font_name(font_number), size);
489   if (!font)
490   {
491     return NULL;
492   }
493 
494   // Style
495   style=0;
496   if (italic)
497     style|=TTF_STYLE_ITALIC;
498   if (bold)
499     style|=TTF_STYLE_BOLD;
500   TTF_SetFontStyle(font, style);
501 
502   // Colors: Text will be generated as white on black.
503   fg_color.r=fg_color.g=fg_color.b=255;
504   bg_color.r=bg_color.g=bg_color.b=0;
505   // The following is alpha, supposedly unused
506 #if defined(USE_SDL)
507   bg_color.unused=fg_color.unused=255;
508 #elif defined(USE_SDL2)
509   bg_color.a=fg_color.a=255;
510 #endif
511 
512   // Text rendering: creates a 8bit surface with its dedicated palette
513   #ifdef __ANDROID__
514   if (antialias)
515     text_surface=TTF_RenderUTF8_Shaded(font, str, fg_color, bg_color );
516   else
517     text_surface=TTF_RenderUTF8_Solid(font, str, fg_color);
518   #else
519   if (antialias)
520     text_surface=TTF_RenderText_Shaded(font, str, fg_color, bg_color );
521   else
522     text_surface=TTF_RenderText_Solid(font, str, fg_color);
523   #endif
524   if (!text_surface)
525   {
526     TTF_CloseFont(font);
527     return NULL;
528   }
529 
530   new_brush=Surface_to_bytefield(text_surface, NULL);
531   if (!new_brush)
532   {
533     SDL_FreeSurface(text_surface);
534     TTF_CloseFont(font);
535     return NULL;
536   }
537 
538   // Import palette
539   Get_SDL_Palette(text_surface->format->palette, palette);
540 
541   if (antialias)
542   {
543     int black_col;
544     // Shaded text: X-Swap the color that is pure black with the BG color number,
545     // so that the brush is immediately 'transparent'
546 
547     // Find black (c)
548     for (black_col=0; black_col<256; black_col++)
549     {
550       if (palette[black_col].R==0 && palette[black_col].G==0 && palette[black_col].B==0)
551         break;
552     } // If not found: c = 256 = 0 (byte)
553 
554     if (black_col != Back_color)
555     {
556       int c;
557       byte colmap[256];
558       // Swap palette entries
559 
560       SWAP_BYTES(palette[black_col].R, palette[Back_color].R)
561       SWAP_BYTES(palette[black_col].G, palette[Back_color].G)
562       SWAP_BYTES(palette[black_col].B, palette[Back_color].B)
563 
564       // Define a colormap
565       for (c=0; c<256; c++)
566         colmap[c]=c;
567 
568       // The swap
569       colmap[black_col]=Back_color;
570       colmap[Back_color]=black_col;
571 
572       Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w,text_surface->h, text_surface->w);
573 
574       // Also, make the BG color in brush palette have same RGB values as
575       // the current BG color : this will help for remaps.
576       palette[Back_color].R=Main.palette[Back_color].R;
577       palette[Back_color].G=Main.palette[Back_color].G;
578       palette[Back_color].B=Main.palette[Back_color].B;
579     }
580   }
581   else
582   {
583     // Solid text: Was rendered as white on black. Now map colors:
584     // White becomes FG color, black becomes BG. 2-color palette.
585     // Exception: if BG==FG, FG will be set to black or white - any different color.
586     long index;
587     byte new_fore=Fore_color;
588 
589     if (Fore_color==Back_color)
590     {
591       new_fore=Best_color_perceptual_except(Main.palette[Back_color].R, Main.palette[Back_color].G, Main.palette[Back_color].B, Back_color);
592     }
593 
594     for (index=0; index < text_surface->w * text_surface->h; index++)
595     {
596       if (palette[*(new_brush+index)].G < 128)
597         *(new_brush+index)=Back_color;
598       else
599         *(new_brush+index)=new_fore;
600     }
601 
602     // Now copy the current palette to brushe's, for consistency
603     // with the indices.
604     memcpy(palette, Main.palette, sizeof(T_Palette));
605 
606   }
607   *width=text_surface->w;
608   *height=text_surface->h;
609   SDL_FreeSurface(text_surface);
610   TTF_CloseFont(font);
611   return new_brush;
612 }
613 #endif
614 
615 #if defined(WIN32)
Render_text_Win32(const char * str,int font_number,int size,int antialias,int bold,int italic,int * width,int * height,T_Palette palette)616 byte *Render_text_Win32(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette)
617 {
618   int str_len;
619   HGDIOBJ oldobj;
620   HGDIOBJ oldfont;
621   RECT rect;
622   BITMAPINFO *bi;
623   HDC dc;
624   HBITMAP bm;
625   SIZE s;
626   byte * pixels = NULL;
627   byte * new_brush = NULL;
628   int i;
629   int x, y;
630   HFONT font;
631   const char * font_name;
632 
633   font_name = Font_name(font_number);
634 
635   font = CreateFontA(size, 0, 0, 0 /* nOrientation */,
636                      bold ? FW_BOLD : FW_REGULAR, italic, 0 /* underline */, 0 /*strikeout */,
637                      ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
638                      antialias ? ANTIALIASED_QUALITY : NONANTIALIASED_QUALITY /* DEFAULT_QUALITY*/,
639                      DEFAULT_PITCH | FF_DONTCARE, font_name);
640   if (font == NULL)
641     return NULL;
642 
643   dc = CreateCompatibleDC(NULL);
644   oldfont = SelectObject(dc, font);
645   str_len = (int)strlen(str);
646   if (!GetTextExtentPoint32A(dc, str, str_len, &s))
647   {
648     s.cx = 320;
649     s.cy = 32;
650   }
651 
652   bi = (BITMAPINFO*)_alloca(sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
653   memset(bi, 0, sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * 256);
654   bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
655 	bi->bmiHeader.biWidth = (s.cx + 3) & ~3;
656 	bi->bmiHeader.biHeight = -s.cy;
657 	bi->bmiHeader.biPlanes = 1;
658 	bi->bmiHeader.biBitCount = antialias ? 32 : 8; // the GDI does Antialiasing only on TrueColor DIB
659 	bi->bmiHeader.biCompression = BI_RGB;
660 
661   for (i = 0; i < 256; i++) {
662     bi->bmiColors[i].rgbRed = i;
663     bi->bmiColors[i].rgbGreen = i;
664     bi->bmiColors[i].rgbBlue = i;
665     palette[i].R = i;
666     palette[i].G = i;
667     palette[i].B = i;
668   }
669   bm = CreateDIBSection(dc, bi, DIB_RGB_COLORS, (void **)&pixels, NULL, 0);
670   oldobj = SelectObject(dc, bm);
671 
672   SetTextColor(dc, RGB(255,255,255));
673   SetBkColor(dc, RGB(0,0,0));
674   SetBkMode(dc, OPAQUE);
675   rect.left=0;
676   rect.top=0;
677   rect.right = s.cx;
678   rect.bottom = s.cy;
679   DrawTextA(dc, str, str_len, &rect, DT_LEFT | DT_SINGLELINE | DT_NOCLIP | DT_NOPREFIX ) ;
680   GdiFlush();
681   SelectObject(dc, oldobj);
682   SelectObject(dc, oldfont);
683 
684   new_brush = (byte *)malloc(s.cx*s.cy);
685   if (antialias)
686   {
687     for (y = 0; y < s.cy; y++)
688     {
689       // get the value from the 1st color component.
690       for (x = 0; x < s.cx; x++)
691         new_brush[x + y * s.cx] = pixels[(x + y * bi->bmiHeader.biWidth) * 4];
692     }
693   }
694   else
695   {
696     for (y = 0; y < s.cy; y++)
697     {
698       for (x = 0; x < s.cx; x++)
699       {
700         byte v = pixels[y*bi->bmiHeader.biWidth+x];
701         new_brush[y*s.cx+x] = (v != 0) ? Fore_color : Back_color;
702       }
703     }
704     memcpy(palette, Main.palette, sizeof(T_Palette));
705   }
706   *width = s.cx;
707   *height = s.cy;
708 
709   DeleteObject(bm);
710   ReleaseDC(NULL, dc);
711   DeleteObject(font);
712   return new_brush;
713 }
714 #endif
715 
Render_text_SFont(const char * str,int font_number,int * width,int * height,T_Palette palette)716 byte *Render_text_SFont(const char *str, int font_number, int *width, int *height, T_Palette palette)
717 {
718   SFont_Font *font;
719   T_GFX2_Surface * text_surface;
720   T_GFX2_Surface *font_surface;
721   byte * new_brush = NULL;
722 
723   // Chargement de la fonte
724   font_surface = Load_surface(Font_name(font_number), NULL, NULL);
725   if (!font_surface)
726   {
727     Verbose_message("Warning", "Error loading font");
728     // TODO this leaves a non-erased cursor when the window closes.
729     return NULL;
730   }
731   font=SFont_InitFont(font_surface);
732   if (!font)
733   {
734     GFX2_Log(GFX2_ERROR, "Font init failed : %s\n", Font_name(font_number));
735     Free_GFX2_Surface(font_surface);
736     return NULL;
737   }
738 
739   // Calcul des dimensions
740   *height = SFont_TextHeight(font, str);
741   *width = SFont_TextWidth(font, str);
742 
743   text_surface = New_GFX2_Surface(*width, *height);
744   if (text_surface == NULL)
745   {
746     GFX2_Log(GFX2_WARNING, "Failed to allocate text surface\n");
747     SFont_FreeFont(font);
748     return NULL;
749   }
750   // Fill with transparent color
751   memset(text_surface->pixels, font->Transparent, *width * *height);
752   // Rendu du texte
753   SFont_Write(text_surface, font, 0, 0, str);
754 
755   // Copy palette
756   memcpy(palette, font_surface->palette, sizeof(T_Palette));
757 
758   new_brush = text_surface->pixels; // "Steal" pixels from surface
759 
760   // Swap current BG color with font's transparent color
761   if (font->Transparent != Back_color)
762   {
763     int c;
764     byte colmap[256];
765     // Swap palette entries
766 
767     SWAP_BYTES(palette[font->Transparent].R, palette[Back_color].R)
768     SWAP_BYTES(palette[font->Transparent].G, palette[Back_color].G)
769     SWAP_BYTES(palette[font->Transparent].B, palette[Back_color].B)
770 
771     // Define a colormap
772     for (c=0; c<256; c++)
773       colmap[c]=c;
774 
775     // The swap
776     colmap[font->Transparent]=Back_color;
777     colmap[Back_color]=font->Transparent;
778 
779     Remap_general_lowlevel(colmap, new_brush, new_brush, text_surface->w, text_surface->h, text_surface->w);
780 
781   }
782 
783   SFont_FreeFont(font);
784   free(text_surface); // Do not call Free_GFX2_Surface() because pixels was stolen
785 
786   return new_brush;
787 }
788 
789 // Crée une brosse à partir des paramètres de texte demandés.
790 // Si cela réussit, la fonction place les dimensions dans width et height,
791 // et retourne l'adresse du bloc d'octets.
Render_text(const char * str,int font_number,int size,int antialias,int bold,int italic,int * width,int * height,T_Palette palette)792 byte *Render_text(const char *str, int font_number, int size, int antialias, int bold, int italic, int *width, int *height, T_Palette palette)
793 {
794   T_Font *font = font_list_start;
795   int index=font_number;
796   #if defined(NOTTF) && !defined(WIN32)
797     (void) size; // unused
798     (void) antialias; // unused
799     (void) bold; // unused
800     (void) italic; // unused
801   #endif
802 
803   // Verification type de la fonte
804   if (font_number < 0 || font == NULL)
805     return NULL;
806 
807   while (index--)
808   {
809     font = font->Next;
810     if (font == NULL)
811       return NULL;
812   }
813   if (font->Is_truetype)
814   {
815   #if !defined(NOTTF)
816     return Render_text_TTF(str, font_number, size, antialias, bold, italic, width, height, palette);
817   #elif defined(WIN32)
818     return Render_text_Win32(str, font_number, size, antialias, bold, italic, width, height, palette);
819   #else
820     return NULL;
821   #endif
822   }
823   else
824   {
825     return Render_text_SFont(str, font_number, width, height, palette);
826   }
827 }
828