1 /*
2   fonts.c
3 
4   Copyright (c) 2009-2020
5   http://www.tuxpaint.org/
6 
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11 
12   This program 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 this program; if not, write to the Free Software
19   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20   (See COPYING.txt)
21 
22   $Id$
23 */
24 
25 #include <stdio.h>
26 #ifndef __USE_GNU
27 #define __USE_GNU               /* for strcasestr() */
28 #endif
29 #include <string.h>
30 #include <stdlib.h>
31 #include <locale.h>
32 
33 #include <errno.h>
34 
35 #include <libintl.h>
36 #ifndef gettext_noop
37 #define gettext_noop(String) String
38 #endif
39 
40 /*
41 	The following section renames global variables defined in SDL_Pango.h to avoid errors during linking.
42 	It is okay to rename these variables because they are constants.
43 	SDL_Pang.h is included by fonts.h.
44 */
45 #define _MATRIX_WHITE_BACK _MATRIX_WHITE_BACK2
46 #define MATRIX_WHITE_BACK MATRIX_WHITE_BACK2
47 #define _MATRIX_BLACK_BACK _MATRIX_BLACK_BACK2
48 #define MATRIX_BLACK_BACK MATRIX_BLACK_BACK2
49 #define _MATRIX_TRANSPARENT_BACK_BLACK_LETTER _MATRIX_TRANSPARENT_BACK_BLACK_LETTER2
50 #define MATRIX_TRANSPARENT_BACK_BLACK_LETTER MATRIX_TRANSPARENT_BACK_BLACK_LETTER2
51 #define _MATRIX_TRANSPARENT_BACK_WHITE_LETTER _MATRIX_TRANSPARENT_BACK_WHITE_LETTER2
52 #define MATRIX_TRANSPARENT_BACK_WHITE_LETTER MATRIX_TRANSPARENT_BACK_WHITE_LETTER2
53 #define _MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER _MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER2
54 #define MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER MATRIX_TRANSPARENT_BACK_TRANSPARENT_LETTER2
55 /*
56 	The renaming ends here.
57 */
58 
59 #include "platform.h"
60 #include "fonts.h"
61 #include "i18n.h"
62 #include "progressbar.h"
63 #include "dirwalk.h"
64 #include "get_fname.h"
65 #include "debug.h"
66 
67 #ifdef WIN32
68 #include "win32_print.h"
69 #endif
70 
71 #if defined(__MACOS__)
72 #include "macos.h"
73 #elif defined(__IOS__)
74 #include "ios.h"
75 #endif
76 
77 #ifdef __HAIKU__
78 #include <FindDirectory.h>
79 #include <fs_info.h>
80 #endif
81 
82 /* system fonts that cause TTF_OpenFont to crash */
83 static const char *problemFonts[] = {
84   "/Library/Fonts//AppleMyungjo.ttf",
85   NULL
86 };
87 
88 /* font types that cause TTF_OpenFont to crash */
89 static const char *problemFontExtensions[] = {
90   ".pfb",                       /* Ubuntu 14.04 (libsdl-ttf2.0-0 2.0.11-3, libfreetype6 2.5.2-1ubuntu2) -bjk 2014.04.19 */
91   NULL
92 };
93 
94 #ifdef FORKED_FONTS
95 
96 #include <sys/socket.h>
97 #include <unistd.h>
98 #include <fcntl.h>
99 #include <sys/poll.h>
100 #include <sys/wait.h>
101 
102 #ifdef _POSIX_PRIORITY_SCHEDULING
103 #include <sched.h>
104 #else
105 #define sched_yield()
106 #endif
107 
108 #ifdef __linux__
109 #include <sys/prctl.h>
110 #else
111 #define prctl(o,a1)
112 #define PR_SET_PDEATHSIG 0
113 #endif
114 
115 #endif
116 
117 #ifndef FORKED_FONTS
118 SDL_Thread *font_thread;
119 #endif
120 
121 #ifndef NO_SDLPANGO
122 
123 #include "SDL_Pango.h"
124 #if !defined(SDL_PANGO_H)
125 #error "---------------------------------------------------"
126 #error "If you installed SDL_Pango from a package, be sure"
127 #error "to get the development package, as well!"
128 #error "(e.g., 'libsdl-pango1-dev.rpm')"
129 #error "---------------------------------------------------"
130 #endif
131 
132 #endif
133 
134 
135 #ifdef FORKED_FONTS
136 int no_system_fonts;
137 #else
138 int no_system_fonts = 1;
139 #endif
140 int all_locale_fonts;
141 volatile long font_thread_done;
142 volatile long font_thread_aborted;
143 volatile long waiting_for_fonts;
144 static int font_scanner_pid;
145 int font_socket_fd;
146 
147 TuxPaint_Font *medium_font, *small_font, *large_font, *locale_font;
148 
149 family_info **user_font_families;
150 int num_font_families;
151 static int num_font_families_max;
152 
153 style_info **user_font_styles;
154 int num_font_styles;
155 int num_font_styles_max;
156 
157 int text_state;
158 unsigned text_size = 4;         // initial text size
159 
160 int button_label_y_nudge;
161 
162 #ifdef FORKED_FONTS
163 static void reliable_read(int fd, void *buf, size_t count);
164 #endif
165 
166 
167 #ifdef NO_SDLPANGO
load_locale_font(TuxPaint_Font * fallback,int size)168 TuxPaint_Font *load_locale_font(TuxPaint_Font * fallback, int size)
169 {
170   TuxPaint_Font *ret = NULL;
171 
172   if (!need_own_font)
173     {
174       return fallback;
175     }
176   else
177     {
178       char str[128];
179 
180       snprintf(str, sizeof(str), "%sfonts/locale/%s.ttf", DATA_PREFIX, lang_prefix);
181 
182       ret = TuxPaint_Font_OpenFont("", str, size);
183 
184 #ifdef __APPLE__
185       if (!ret)
186         {
187           snprintf(str, sizeof(str), "%sfonts/%s.ttf", DATA_PREFIX, lang_prefix);
188           ret = TuxPaint_Font_OpenFont("", str, size);
189         }
190 
191       if (!ret)
192         {
193           snprintf(str, sizeof(str), "/Library/Fonts/%s.ttf", lang_prefix);
194           ret = TuxPaint_Font_OpenFont("", str, size);
195         }
196 
197       if (!ret)
198         {
199           snprintf(str, sizeof(str), "%s/%s.ttf", apple_fontsPath(), lang_prefix);
200           ret = TuxPaint_Font_OpenFont("", str, size);
201         }
202 #endif
203 
204 /* Not sure why this is like this; we're in a function that's not
205    even defined, unless NO_SDLPANGO is set, so this can't happen
206    -bjk 2017.10.15 */
207 /*
208 #ifndef NO_SDLPANGO
209       if (!ret)
210         {
211           ret = try_alternate_font(size);
212           if (!ret)
213             {
214               fprintf(stderr,
215                       "\nWarning: Can't load font for this locale:\n"
216                       "%s\n"
217                       "The Simple DirectMedia Layer error that occurred was:\n"
218                       "%s\n\n" "Will use default (American English) instead.\n\n", str, SDL_GetError());
219               button_label_y_nudge = smash_i18n();
220             }
221         }
222 #endif
223 */
224       return ret ? ret : fallback;
225     }
226 }
227 #endif
228 
TuxPaint_Font_CloseFont(TuxPaint_Font * tpf)229 void TuxPaint_Font_CloseFont(TuxPaint_Font * tpf)
230 {
231 #ifdef DEBUG
232   printf("TuxPaint_Font_CloseFont step 1 (%p)\n", tpf); //EP
233 #endif
234   if (!tpf)
235     return;                     //EP
236 
237 #ifndef NO_SDLPANGO
238 #ifdef DEBUG
239   printf("TuxPaint_Font_CloseFont step 2 (%p, %d)\n", tpf->pango_context, tpf->typ);    //EP
240 #endif
241   if (tpf->typ == FONT_TYPE_PANGO)
242     if (tpf->pango_context)     //EP
243       {
244 #ifndef __APPLE__               //EP added ifdef because SDLPango_FreeContext sometimes crashed with "pointer being freed was not allocated"
245         SDLPango_FreeContext(tpf->pango_context);
246 #endif
247         tpf->pango_context = NULL;
248       }
249 #endif
250 
251 #ifdef DEBUG
252   printf("TuxPaint_Font_CloseFont step 3 (%p, %d)\n", tpf->ttf_font, tpf->typ); //EP
253   fflush(stdout);
254 #endif
255   if (tpf->typ == FONT_TYPE_TTF)
256     if (tpf->ttf_font)          //EP
257       {
258         TTF_CloseFont(tpf->ttf_font);
259         tpf->ttf_font = NULL;
260       }
261 
262   if (tpf->desc != NULL)
263     {
264       free(tpf->desc);
265       tpf->desc = NULL;
266     }
267 
268   free(tpf);
269 }
270 
TuxPaint_Font_OpenFont(const char * pangodesc,const char * ttffilename,int size)271 TuxPaint_Font *TuxPaint_Font_OpenFont(const char *pangodesc, const char *ttffilename, int size)
272 {
273   TuxPaint_Font *tpf = NULL;
274   int i;
275 
276 #ifndef NO_SDLPANGO
277   char desc[1024];
278 #endif
279 
280 #ifdef DEBUG
281   printf("OpenFont(pango:\"%s\", ttf:\"%s\")\n", pangodesc, ttffilename);
282 #endif
283 
284 #ifndef NO_SDLPANGO
285 
286   if (pangodesc != NULL && pangodesc[0] != '\0')
287     {
288       tpf = (TuxPaint_Font *) malloc(sizeof(TuxPaint_Font));
289       tpf->typ = FONT_TYPE_PANGO;
290       snprintf(desc, sizeof(desc), "%s %d", pangodesc, (size * 3) / 4);
291       tpf->desc = strdup(desc);
292 
293 #ifdef DEBUG
294       printf("Creating context: \"%s\"\n", desc);
295 #endif
296 
297       tpf->pango_context = SDLPango_CreateContext_GivenFontDesc(desc);
298       if (tpf->pango_context == NULL)
299         {
300 #ifdef DEBUG
301           printf("Failed to load %s\n", desc);
302 #endif
303           free(tpf);
304           tpf = NULL;
305         }
306       else
307         tpf->height = size;     /* FIXME: Is this accurate!? -bjk 2007.07.12 */
308 
309 #ifdef DEBUG
310       printf("TuxPaint_Font_OpenFont() done\n");
311       fflush(stdout);
312 #endif
313 
314       return (tpf);
315     }
316 #endif
317 
318   if (ttffilename != NULL && ttffilename[0] != '\0')
319     {
320 #ifdef DEBUG
321       printf("Opening TTF\n");
322       fflush(stdout);
323 #endif
324 
325       i = 0;
326       while (problemFonts[i] != NULL)
327         {
328           if (!strcmp(ttffilename, problemFonts[i++]))
329             return NULL;        /* bail on known problematic fonts that cause TTF_OpenFont to crash */
330         }
331 
332       i = 0;
333       while (problemFontExtensions[i] != NULL)
334         {
335           if (strstr(ttffilename, problemFontExtensions[i++]))
336             return NULL;        /* bail on known problematic font types that cause TTF_OpenFont to crash */
337         }
338 
339       tpf = (TuxPaint_Font *) malloc(sizeof(TuxPaint_Font));
340       tpf->typ = FONT_TYPE_TTF;
341       tpf->ttf_font = TTF_OpenFont(ttffilename, size);
342       tpf->desc = strdup(ttffilename);
343 
344 #ifdef DEBUG
345       printf("Loaded %s: %d->%d\n", ttffilename, tpf, tpf->ttf_font);
346       fflush(stdout);
347 #endif
348 
349       if (tpf->ttf_font == NULL)
350         {
351 #ifdef DEBUG
352           printf("Failed to load %s: %s\n", ttffilename, SDL_GetError());
353 #endif
354           free(tpf);
355           tpf = NULL;
356         }
357       else
358         {
359 #ifdef DEBUG
360           printf("Succeeded loading %s\n", ttffilename);
361 #endif
362           tpf->height = TTF_FontHeight(tpf->ttf_font);
363         }
364     }
365 
366 #ifdef DEBUG
367   printf("TuxPaint_Font_OpenFont() done\n");
368   fflush(stdout);
369 #endif
370 
371   return (tpf);
372 }
373 
374 
375 #ifdef FORKED_FONTS
376 
reliable_write(int fd,const void * buf,size_t count)377 void reliable_write(int fd, const void *buf, size_t count)
378 {
379   struct pollfd p;
380 
381   do
382     {
383       ssize_t rc = write(fd, buf, count);
384 
385       if (rc == -1)
386         {
387           switch (errno)
388             {
389             default:
390               return;
391             case EAGAIN:
392             case ENOSPC:
393               ;                 // satisfy a C syntax abomination
394               p = (struct pollfd)
395               {
396               fd, POLLOUT, 0};
397               poll(&p, 1, -1);  // try not to burn CPU time
398               // FALL THROUGH
399             case EINTR:
400               continue;
401             }
402         }
403       buf += rc;
404       count -= rc;
405     }
406   while (count);
407 }
408 
409 
reliable_read(int fd,void * buf,size_t count)410 static void reliable_read(int fd, void *buf, size_t count)
411 {
412   struct pollfd p;
413 
414   do
415     {
416       ssize_t rc = read(fd, buf, count);
417 
418       if (rc == -1)
419         {
420           switch (errno)
421             {
422             default:
423               return;
424             case EAGAIN:
425               ;                 // satisfy a C syntax abomination
426               p = (struct pollfd)
427               {
428               fd, POLLIN, 0};
429               poll(&p, 1, -1);  // try not to burn CPU time
430               // FALL THROUGH
431             case EINTR:
432               continue;
433             }
434         }
435       if (rc == 0)
436         break;                  // EOF. Better not happen before the end!
437       buf += rc;
438       count -= rc;
439     }
440   while (count);
441 }
442 
443 #endif
444 
groupfonts_range(style_info ** base,int count)445 static void groupfonts_range(style_info ** base, int count)
446 {
447   int boldcounts[4] = { 0, 0, 0, 0 };
448   int boldmap[4] = { -1, -1, -1, -1 };
449   int i;
450   int boldmax;
451   int boldmin;
452   int bolduse;
453   int spot;
454   family_info *fi;
455 
456 #if 0
457 // THREADED_FONTS
458   if (count < 1 || count > 4)
459     {
460       printf("\n::::::: %d styles in %s:\n", count, base[0]->family);
461       i = count;
462       while (i--)
463         {
464           printf("               %s\n", base[i]->style);
465         }
466     }
467 #endif
468 
469   i = count;
470   while (i--)
471     boldcounts[base[i]->boldness]++;
472 
473   boldmax = base[0]->boldness;
474   boldmin = base[0]->boldness;
475   bolduse = 0;
476 
477   i = 4;
478   while (i--)
479     {
480       if (!boldcounts[i])
481         continue;
482       if (i > boldmax)
483         boldmax = i;
484       if (i < boldmin)
485         boldmin = i;
486       bolduse++;
487     }
488   if (likely(bolduse <= 2))
489     {
490       // in case they are same, we want non-bold,
491       // so that setting goes second
492       boldmap[boldmax] = 1;
493       boldmap[boldmin] = 0;
494     }
495   else if (count == 3)
496     {
497       int boldmid;
498       int zmin = 0, zmid = 0, zmax = 0;
499 
500       boldmap[boldmax] = 1;
501       boldmap[boldmin] = 0;
502       boldmid = boldcounts[boldmin + 1] ? boldmin + 1 : boldmin + 2;
503 
504       i = 3;
505       while (i--)
506         {
507           if (base[i]->boldness == boldmin)
508             zmin = base[i]->italic;
509           if (base[i]->boldness == boldmid)
510             zmid = base[i]->italic;
511           if (base[i]->boldness == boldmax)
512             zmax = base[i]->italic;
513         }
514       if (zmin != zmid)
515         boldmap[boldmid] = 0;
516       else if (zmid != zmax)
517         boldmap[boldmid] = 1;
518       else if (boldmin == 0 && boldmid == 1)
519         {
520           boldmap[0] = -1;
521           boldmap[1] = 0;
522         }
523     }
524   else
525     {
526       int claimed_bold = boldcounts[3];
527       int claimed_norm = boldcounts[1];
528 
529       // 3 or 4 boldness levels, 4 or more styles!
530       // This is going to be random hacks and hopes.
531 
532       // bold is bold
533       boldmap[3] = 1;
534 
535       // norm is norm
536       boldmap[1] = 0;
537 
538       // classify demi-bold or medium
539       if (claimed_bold < 2)
540         {
541           boldmap[2] = 1;
542           claimed_bold += boldcounts[2];
543         }
544       else if (claimed_norm < 2)
545         {
546           boldmap[2] = 0;
547           claimed_norm += boldcounts[2];
548         }
549 
550       // classify lightface
551       if (claimed_norm < 2)
552         {
553           boldmap[0] = 0;
554           //claimed_norm += boldcounts[0];
555         }
556     }
557 
558   if (num_font_families == num_font_families_max)
559     {
560       num_font_families_max = num_font_families_max * 5 / 4 + 30;
561       user_font_families = realloc(user_font_families, num_font_families_max * sizeof *user_font_families);
562     }
563 
564   fi = calloc(1, sizeof *fi);
565   user_font_families[num_font_families++] = fi;
566   fi->directory = strdup(base[0]->directory);
567   fi->family = strdup(base[0]->family);
568   fi->score = base[0]->truetype + base[0]->score;
569   i = count;
570   while (i--)
571     {
572       int b = boldmap[base[i]->boldness];
573 
574       if (b == -1)
575         {
576 #if 0
577 // THREADED_FONTS
578           printf("too many boldness levels, discarding: %s, %s\n", base[i]->family, base[i]->style);
579 #endif
580           continue;
581         }
582       spot = b ? TTF_STYLE_BOLD : 0;
583       spot += base[i]->italic ? TTF_STYLE_ITALIC : 0;
584       if (fi->filename[spot])
585         {
586 #if 0
587 // THREADED_FONTS
588           printf("duplicates, discarding: %s, %s\n", base[i]->family, base[i]->style);
589           printf("b %d, spot %d\n", b, spot);
590           printf("occupancy %p %p %p %p\n", fi->filename[0], fi->filename[1], fi->filename[2], fi->filename[3]);
591 #endif
592           continue;
593         }
594       fi->filename[spot] = strdup(base[i]->filename);
595       fi->score += 2;
596     }
597   if (!fi->filename[0] && !fi->filename[1])
598     {
599       fi->filename[0] = fi->filename[2];
600       fi->filename[2] = NULL;
601       fi->filename[1] = fi->filename[3];
602       fi->filename[3] = NULL;
603     }
604   if (!fi->filename[0] && !fi->filename[2])
605     {
606       fi->filename[0] = fi->filename[1];
607       fi->filename[1] = NULL;
608       fi->filename[2] = fi->filename[3];
609       fi->filename[3] = NULL;
610     }
611   if (!fi->filename[0])
612     {
613       fi->filename[0] = strdup(fi->filename[TTF_STYLE_BOLD]);
614     }
615 }
616 
617 
618 // void qsort(void *base, size_t nmemb, size_t size,
619 // int(*compar)(const void *, const void *));
620 
621 
622 // For qsort() and other use, to see if font files are groupable
compar_fontgroup(const void * v1,const void * v2)623 static int compar_fontgroup(const void *v1, const void *v2)
624 {
625   const style_info *s1 = *(style_info **) v1;
626   const style_info *s2 = *(style_info **) v2;
627   int rc;
628 
629   rc = strcmp(s1->directory, s2->directory);
630   if (rc)
631     return rc;
632 
633   rc = s1->truetype - s2->truetype;
634   if (rc)
635     return rc;
636 
637   return strcmp(s1->family, s2->family);
638 }
639 
640 
641 // For qsort() and other use, to see if font files are duplicates
compar_fontkiller(const void * v1,const void * v2)642 static int compar_fontkiller(const void *v1, const void *v2)
643 {
644   const family_info *f1 = *(family_info **) v1;
645   const family_info *f2 = *(family_info **) v2;
646   int rc;
647 
648   rc = strcmp(f1->family, f2->family);
649   if (rc)
650     return rc;
651 
652   return f1->score - f2->score;
653 }
654 
655 
656 // For qsort() and other use, to order the worst ones last
compar_fontscore(const void * v1,const void * v2)657 static int compar_fontscore(const void *v1, const void *v2)
658 {
659   const family_info *f1 = *(family_info **) v1;
660   const family_info *f2 = *(family_info **) v2;
661 
662   return f2->score - f1->score;
663 }
664 
665 
666 // Font style names are a mess that we must try to make
667 // sense of. For example...
668 //
669 // Cooper: Light, Medium, Light Bold, Black
670 // HoeflerText: (nil), Black
parse_font_style(style_info * si)671 static void parse_font_style(style_info * si)
672 {
673   int have_light = 0;
674   int have_demi = 0;
675   int have_bold = 0;
676   int have_medium = 0;
677   int have_black = 0;
678   int have_heavy = 0;
679 
680   int stumped = 0;
681   char *sp = si->style;
682 
683   si->italic = 0;
684 
685 
686   while (*sp)
687     {
688       if (*sp == ' ')
689         {
690           sp++;
691           continue;
692         }
693       if (!strncasecmp(sp, "Bold", strlen("Bold")))
694         {
695           sp += strlen("Bold");
696           have_bold = 1;
697           continue;
698         }
699       if (!strncasecmp(sp, "Regular", strlen("Regular")))
700         {
701           sp += strlen("Regular");
702           continue;
703         }
704       if (!strncasecmp(sp, "Italic", strlen("Italic")))
705         {
706           sp += strlen("Italic");
707           si->italic = 1;
708           continue;
709         }
710       if (!strncasecmp(sp, "Oblique", strlen("Oblique")))
711         {
712           sp += strlen("Oblique");
713           si->italic = 1;
714           continue;
715         }
716       // move " Condensed" from style to family
717       if (!strncasecmp(sp, "Condensed", strlen("Condensed")))
718         {
719           size_t len = strlen(si->family);
720           char *name = malloc(len + strlen(" Condensed") + 1);
721 
722           sp += strlen("Condensed");
723           memcpy(name, si->family, len);
724           strcpy(name + len, " Condensed");
725           free(si->family);
726           si->family = name;
727           continue;
728         }
729       if (!strncasecmp(sp, "Light", strlen("Light")))
730         {
731           sp += strlen("Light");
732           have_light = 1;
733           continue;
734         }
735       if (!strncasecmp(sp, "Medium", strlen("Medium")))
736         {
737           sp += strlen("Medium");
738           have_medium = 1;
739           continue;
740         }
741       if (!strncasecmp(sp, "Demi", strlen("Demi")))
742         {
743           sp += strlen("Demi");
744           have_demi = 1;
745           continue;
746         }
747       if (!strncasecmp(sp, "Heavy", strlen("Heavy")))
748         {
749           sp += strlen("Heavy");
750           have_heavy = 1;
751           continue;
752         }
753       if (!strncasecmp(sp, "Normal", strlen("Normal")))
754         {
755           sp += strlen("Normal");
756           continue;
757         }
758       if (!strncasecmp(sp, "Black", strlen("Black")))
759         {
760           sp += strlen("Black");
761           have_black = 1;
762           continue;
763         }
764       if (!strncasecmp(sp, "Roman", strlen("Roman")))
765         {
766           sp += strlen("Roman");
767           continue;
768         }
769       if (!strncasecmp(sp, "Book", strlen("Book")))
770         {
771           sp += strlen("Book");
772           continue;
773         }
774       if (!strncasecmp(sp, "Chancery", strlen("Chancery")))
775         {
776           sp += strlen("Chancery");
777           si->italic = 1;
778           continue;
779         }
780       if (!strncasecmp(sp, "Thin", strlen("Thin")))
781         {
782           sp += strlen("Thin");
783           have_light = 1;
784           continue;
785         }
786       if (!strncmp(sp, "LR", strlen("LR")))
787         {
788           sp += strlen("LR");
789           continue;
790         }
791 
792       if (!stumped)
793         {
794           stumped = 1;
795 #if 0
796 // THREADED_FONTS
797           printf("Font style parser stumped by \"%s\".\n", si->style);
798 #endif
799         }
800       sp++;                     // bad: an unknown character
801     }
802 
803 
804   if (have_demi || have_medium)
805     si->boldness = 2;
806   else if (have_bold || have_black || have_heavy)       // TODO: split these
807     si->boldness = 3;
808   else if (have_light)
809     si->boldness = 0;
810   else
811     si->boldness = 1;
812 
813   // we'll count both TrueType and OpenType
814   si->truetype = ! !strcasestr(si->filename, ".ttf") || ! !strcasestr(si->filename, ".otf");
815 }
816 
817 
dupe_markdown_range(family_info ** base,int count)818 static void dupe_markdown_range(family_info ** base, int count)
819 {
820   int bestscore = -999;
821   int bestslot = 0;
822   int i = count;
823 
824   while (i--)
825     {
826       int score = base[i]->score;
827 
828       if (score <= bestscore)
829         continue;
830       bestscore = score;
831       bestslot = i;
832     }
833   i = count;
834   while (i--)
835     {
836       if (i == bestslot)
837         continue;
838       base[i]->score = -999;
839     }
840 }
841 
842 
groupfonts(void)843 static void groupfonts(void)
844 {
845   char **cpp;
846   int i = num_font_styles;
847   int low = 0;
848 
849   while (i--)
850     parse_font_style(user_font_styles[i]);
851 
852   qsort(user_font_styles, num_font_styles, sizeof user_font_styles[0], compar_fontgroup);
853   //printf("groupfonts() qsort(user_font_styles...)\n");
854   //fflush(stdout);
855 
856   for (;;)
857     {
858       int high = low;
859 
860       if (low >= num_font_styles)
861         break;
862       for (;;)
863         {
864           if (++high >= num_font_styles)
865             break;
866           if (compar_fontgroup(user_font_styles + low, user_font_styles + high))
867             break;
868         }
869       groupfonts_range(user_font_styles + low, high - low);
870       low = high;
871     }
872 
873   i = num_font_styles;
874   while (i--)
875     {
876       free(user_font_styles[i]->filename);
877       free(user_font_styles[i]->directory);
878       free(user_font_styles[i]->family);
879       free(user_font_styles[i]->style);
880       free(user_font_styles[i]);
881     }
882   free(user_font_styles);
883   user_font_styles = NULL;      // just to catch bugs
884 
885   qsort(user_font_families, num_font_families, sizeof user_font_families[0], compar_fontkiller);
886   low = 0;
887   for (;;)
888     {
889       int high = low;
890 
891       if (low >= num_font_families)
892         break;
893       for (;;)
894         {
895           if (++high >= num_font_families)
896             break;
897           if (strcmp(user_font_families[low]->family, user_font_families[high]->family))
898             break;
899         }
900       dupe_markdown_range(user_font_families + low, high - low);
901       low = high;
902     }
903   qsort(user_font_families, num_font_families, sizeof user_font_families[0], compar_fontscore);
904   //printf("groupfonts() qsort(user_font_families 2...)\n");
905   //fflush(stdout);
906   if (num_font_families > 0 && user_font_families[0]->score < 0)
907     fprintf(stderr, "sorted the wrong way, or all fonts were unusable\n");
908 #if 0
909 // THREADED_FONTS
910   printf("Trim starting with %d families\n", num_font_families);
911 #endif
912   while (num_font_families > 1 && user_font_families[num_font_families - 1]->score < 0)
913     {
914       i = --num_font_families;
915       free(user_font_families[i]->directory);
916       free(user_font_families[i]->family);
917       cpp = user_font_families[i]->filename;
918       if (cpp[0])
919         free(cpp[0]);
920       if (cpp[1])
921         free(cpp[1]);
922       if (cpp[2])
923         free(cpp[2]);
924       if (cpp[3])
925         free(cpp[3]);
926       free(user_font_families[i]);
927       user_font_families[i] = NULL;
928     }
929 #if 0
930 // THREADED_FONTS
931   printf("Trim ending with %d families\n", num_font_families);
932 #endif
933 }
934 
935 
loadfonts_locale_filter(SDL_Surface * screen,const char * const dir,const char * restrict const locale)936 static void loadfonts_locale_filter(SDL_Surface * screen, const char *const dir, const char *restrict const locale)
937 {
938   char buf[TP_FTW_PATHSIZE];
939   unsigned dirlen = strlen(dir);
940 
941   memcpy(buf, dir, dirlen);
942   tp_ftw(screen, buf, dirlen, 1, loadfont_callback, locale);
943 }
944 
loadfonts(SDL_Surface * screen,const char * const dir)945 static void loadfonts(SDL_Surface * screen, const char *const dir)
946 {
947   loadfonts_locale_filter(screen, dir, NULL);
948 }
949 
950 
load_user_fonts(SDL_Surface * screen,void * vp,const char * restrict const locale)951 /* static */ int load_user_fonts(SDL_Surface * screen, void *vp, const char *restrict const locale)
952 {
953   char *homedirdir;
954 
955   (void)vp;                     // junk passed by threading library
956 
957   loadfonts_locale_filter(screen, DATA_PREFIX "fonts", locale);
958 
959   if (!no_system_fonts)
960     {
961 #ifdef WIN32
962       homedirdir = GetSystemFontDir();
963       loadfonts(screen, homedirdir);
964       free(homedirdir);
965 #elif defined(__BEOS__)
966       loadfonts(screen, "/boot/home/config/font/ttffonts");
967       loadfonts(screen, "/usr/share/fonts");
968       loadfonts(screen, "/usr/X11R6/lib/X11/fonts");
969 #elif defined(__HAIKU__)
970       dev_t volume = dev_for_path("/boot");
971       char buffer[B_PATH_NAME_LENGTH + B_FILE_NAME_LENGTH];
972       status_t result;
973 
974       result = find_directory(B_SYSTEM_FONTS_DIRECTORY, volume, false, buffer, sizeof(buffer));
975       loadfonts(screen, buffer);
976       result = find_directory(B_SYSTEM_NONPACKAGED_FONTS_DIRECTORY, volume, false, buffer, sizeof(buffer));
977       loadfonts(screen, buffer);
978       result = find_directory(B_USER_FONTS_DIRECTORY, volume, false, buffer, sizeof(buffer));
979       loadfonts(screen, buffer);
980       result = find_directory(B_USER_NONPACKAGED_FONTS_DIRECTORY, volume, false, buffer, sizeof(buffer));
981       loadfonts(screen, buffer);
982 #elif defined(__APPLE__)
983       loadfonts(screen, "/System/Library/Fonts");
984       loadfonts(screen, "/Library/Fonts");
985       loadfonts(screen, apple_fontsPath());
986       loadfonts(screen, "/usr/share/fonts");
987       loadfonts(screen, "/usr/X11R6/lib/X11/fonts");
988 #elif defined(__sun__)
989       loadfonts(screen, "/usr/openwin/lib/X11/fonts");
990       loadfonts(screen, "/usr/share/fonts");
991       loadfonts(screen, "/usr/X11R6/lib/X11/fonts");
992 #else
993       loadfonts(screen, "/usr/share/feh/fonts");
994       loadfonts(screen, "/usr/share/fonts");
995       loadfonts(screen, "/usr/X11R6/lib/X11/fonts");
996       loadfonts(screen, "/usr/share/texmf/fonts");
997       loadfonts(screen, "/usr/share/grace/fonts/type1");
998       loadfonts(screen, "/usr/share/hatman/fonts");
999       loadfonts(screen, "/usr/share/icewm/themes/jim-mac");
1000       loadfonts(screen, "/usr/share/vlc/skins2/fonts");
1001       loadfonts(screen, "/usr/share/xplanet/fonts");
1002 #endif
1003     }
1004 
1005   homedirdir = get_fname("fonts", DIR_DATA);
1006   loadfonts(screen, homedirdir);
1007   free(homedirdir);
1008 
1009 #ifdef WIN32
1010   homedirdir = get_fname("data/fonts", DIR_DATA);
1011   loadfonts(screen, homedirdir);
1012   free(homedirdir);
1013 #endif
1014 
1015 #ifdef DEBUG
1016   printf("Grouping fonts...\n");
1017   fflush(stdout);
1018 #endif
1019 
1020   groupfonts();
1021 
1022 #ifdef DEBUG
1023   printf("Finished loading the fonts\n");
1024   fflush(stdout);
1025 #endif
1026 
1027   font_thread_done = 1;
1028   waiting_for_fonts = 0;
1029   // FIXME: need a memory barrier here
1030   return 0;                     // useless, wanted by threading library
1031 }
1032 
1033 
1034 #ifdef FORKED_FONTS
1035 
run_font_scanner(SDL_Surface * screen,const char * restrict const locale)1036 void run_font_scanner(SDL_Surface * screen, const char *restrict const locale)
1037 {
1038   int sv[2];
1039   int size, i;
1040   char *buf, *walk;
1041 
1042   if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
1043     exit(42);
1044   font_scanner_pid = fork();
1045   if (font_scanner_pid)
1046     {
1047       // parent (or error -- but we're screwed in that case)
1048       font_socket_fd = sv[0];
1049       close(sv[1]);
1050       return;
1051     }
1052 #ifndef __HAIKU__
1053   /* be nice, letting the main thread get the CPU */
1054   if (nice(42) == -1)
1055     {
1056       fprintf(stderr, "Font scanner thread can't nice() itself\n");
1057     }
1058 #endif
1059   sched_yield();                // try to let the parent run right now
1060   prctl(PR_SET_PDEATHSIG, 9);   // get killed if parent exits
1061   if (getppid() == 1)
1062     _exit(99);                  // parent is already init, and won't be dying :-)
1063   font_socket_fd = sv[1];
1064   close(sv[0]);
1065   progress_bar_disabled = 1;
1066   reliable_read(font_socket_fd, &no_system_fonts, sizeof no_system_fonts);
1067   sched_yield();                // try to let the parent run right now
1068   SDL_Init(SDL_INIT_NOPARACHUTE);
1069   TTF_Init();
1070   load_user_fonts(screen, NULL, locale);
1071 
1072   size = 0;
1073   i = num_font_families;
1074   while (i--)
1075     {
1076       char *s;
1077 
1078       s = user_font_families[i]->directory;
1079       if (s)
1080         size += strlen(s);
1081       s = user_font_families[i]->family;
1082       if (s)
1083         size += strlen(s);
1084       s = user_font_families[i]->filename[0];
1085       if (s)
1086         size += strlen(s);
1087       s = user_font_families[i]->filename[1];
1088       if (s)
1089         size += strlen(s);
1090       s = user_font_families[i]->filename[2];
1091       if (s)
1092         size += strlen(s);
1093       s = user_font_families[i]->filename[3];
1094       if (s)
1095         size += strlen(s);
1096       size += 6;                // for '\0' on each of the above
1097     }
1098   size += 2;                    // for 2-byte font count
1099   buf = malloc(size);
1100   walk = buf;
1101 #ifdef DEBUG
1102   printf("Sending %u bytes with %u families.\n", size, num_font_families);
1103 #endif
1104   *walk++ = num_font_families & 0xffu;
1105   *walk++ = num_font_families >> 8u;
1106   i = num_font_families;
1107   while (i--)
1108     {
1109       int len;
1110       char *s;
1111 
1112       s = user_font_families[i]->directory;
1113       if (s)
1114         {
1115           len = strlen(s);
1116           memcpy(walk, s, len);
1117           walk += len;
1118         }
1119       *walk++ = '\0';
1120 
1121       s = user_font_families[i]->family;
1122       if (s)
1123         {
1124           len = strlen(s);
1125           memcpy(walk, s, len);
1126           walk += len;
1127         }
1128       *walk++ = '\0';
1129 
1130       s = user_font_families[i]->filename[0];
1131       if (s)
1132         {
1133           len = strlen(s);
1134           memcpy(walk, s, len);
1135           walk += len;
1136         }
1137       *walk++ = '\0';
1138 
1139       s = user_font_families[i]->filename[1];
1140       if (s)
1141         {
1142           len = strlen(s);
1143           memcpy(walk, s, len);
1144           walk += len;
1145         }
1146       *walk++ = '\0';
1147 
1148       s = user_font_families[i]->filename[2];
1149       if (s)
1150         {
1151           len = strlen(s);
1152           memcpy(walk, s, len);
1153           walk += len;
1154         }
1155       *walk++ = '\0';
1156 
1157       s = user_font_families[i]->filename[3];
1158       if (s)
1159         {
1160           len = strlen(s);
1161           memcpy(walk, s, len);
1162           walk += len;
1163         }
1164       *walk++ = '\0';
1165     }
1166   reliable_write(font_socket_fd, buf, size);
1167   exit(0);
1168 }
1169 
1170 
receive_some_font_info(SDL_Surface * screen)1171 void receive_some_font_info(SDL_Surface * screen)
1172 {
1173   char *buf = NULL;
1174   unsigned buf_size = 0;
1175   unsigned buf_fill = 0;
1176   ssize_t rc;
1177   struct pollfd p;
1178   int status;
1179   /* unsigned */ char *walk;
1180   unsigned i;
1181   family_info *fip;
1182 
1183   fcntl(font_socket_fd, F_SETFL, O_NONBLOCK);
1184   for (;;)
1185     {
1186       if (buf_size <= buf_fill * 9 / 8 + 128)
1187         {
1188           buf_size = buf_size * 5 / 4 + 256;
1189 
1190           // FIXME: Valgrind says this leaks -bjk 2007.07.19
1191           buf = realloc(buf, buf_size);
1192         }
1193       rc = read(font_socket_fd, buf + buf_fill, buf_size - buf_fill);
1194 #ifdef DEBUG
1195       printf("read: fd=%d buf_fill=%u buf_size=%u rc=%ld\n", font_socket_fd, buf_fill, buf_size, (long int)rc);
1196 #endif
1197 
1198       if (rc == -1)
1199         {
1200           switch (errno)
1201             {
1202             default:
1203               return;
1204             case EAGAIN:
1205               ;                 // satisfy a C syntax abomination
1206               p = (struct pollfd)
1207               {
1208               font_socket_fd, POLLIN, 0};
1209               show_progress_bar(screen);
1210               poll(&p, 1, 29);  // try not to burn CPU time
1211               continue;
1212             case EINTR:
1213               continue;
1214             }
1215         }
1216       buf_fill += rc;
1217       if (!rc || font_thread_aborted)
1218         break;
1219     }
1220   close(font_socket_fd);
1221 
1222   waitpid(font_scanner_pid, &status, 0);
1223   if (WIFSIGNALED(status) || font_thread_aborted)
1224     {
1225       fprintf(stderr, "child killed by signal %u\n", WTERMSIG(status));
1226       user_font_families = NULL;
1227       num_font_families = 0;
1228       font_thread_done = 1;
1229 
1230       return;
1231     }
1232 
1233   show_progress_bar(screen);
1234   walk = buf;
1235   num_font_families = *(unsigned char *)walk++;
1236   num_font_families += *(unsigned char *)walk++ << 8u;
1237 #ifdef DEBUG
1238   printf("Got %u bytes with %u families.\n", buf_fill, num_font_families);
1239 #endif
1240   user_font_families = malloc(num_font_families * sizeof *user_font_families);
1241 
1242   // FIXME: Valgrind says this malloc() is leaked -bjk 2007.07.19
1243   fip = malloc(num_font_families * sizeof **user_font_families);
1244 
1245   i = num_font_families;
1246   while (i--)
1247     {
1248       unsigned len;
1249 
1250       user_font_families[i] = fip + i;
1251 
1252       len = strlen(walk);
1253       user_font_families[i]->directory = len ? walk : NULL;
1254       walk += len + 1;
1255 
1256       len = strlen(walk);
1257       user_font_families[i]->family = len ? walk : NULL;
1258       walk += len + 1;
1259 
1260       len = strlen(walk);
1261       user_font_families[i]->filename[0] = len ? walk : NULL;
1262       walk += len + 1;
1263 
1264       len = strlen(walk);
1265       user_font_families[i]->filename[1] = len ? walk : NULL;
1266       walk += len + 1;
1267 
1268       len = strlen(walk);
1269       user_font_families[i]->filename[2] = len ? walk : NULL;
1270       walk += len + 1;
1271 
1272       len = strlen(walk);
1273       user_font_families[i]->filename[3] = len ? walk : NULL;
1274       walk += len + 1;
1275 
1276       user_font_families[i]->handle = NULL;
1277 
1278       // score left uninitialized
1279     }
1280   font_thread_done = 1;
1281 }
1282 
1283 #endif
1284 
1285 
1286 
1287 
getfonthandle(int desire)1288 TuxPaint_Font *getfonthandle(int desire)
1289 {
1290   int missing = 0;
1291   family_info *fi = user_font_families[desire];
1292   char *name;
1293   char *pathname;
1294   char description[1024];
1295 
1296 #ifdef DEBUG
1297   printf("\ngetfonthandle(%d)...\n", desire);
1298   fflush(stdout);
1299 #endif
1300 
1301   if (fi == NULL)
1302     {
1303 #ifdef DEBUG
1304       printf("getfonthandle(%d) points to a NULL family\n", desire);
1305       fflush(stdout);
1306 #endif
1307       return NULL;
1308     }
1309 
1310   if (fi->filename != NULL)
1311     {
1312 #ifdef DEBUG
1313       printf("Setting 'name' to fi->filename[%d (0x%x)]\n", (int)text_state, (int)text_state);
1314       fflush(stdout);
1315 #endif
1316 
1317       name = fi->filename[text_state];
1318 
1319 #ifdef DEBUG
1320       printf("Which is: %s\n", name);
1321       fflush(stdout);
1322 #endif
1323     }
1324   else
1325     {
1326 #ifdef DEBUG                    //EP fixed typo: replaced DBEUG with DEBUG
1327       printf("fi->filename is NULL\n");
1328       fflush(stdout);
1329 #endif
1330 
1331       name = NULL;
1332     }
1333 
1334   if (fi->handle)
1335     {
1336 #ifdef DEBUG
1337       printf("fi->handle was set (0x%x)\n", (int)(intptr_t) fi->handle);        //EP added (intptr_t) to avoid warning on x64
1338 
1339       fflush(stdout);
1340 #endif
1341       return fi->handle;
1342     }
1343 
1344 #ifdef DEBUG
1345   printf("fi->handle was not yet set\n");
1346   fflush(stdout);
1347 #endif
1348 
1349 
1350 /* FIXME: Doesn't make sense; fi->handle is NULL! -bjk 2007.07.17
1351 
1352 #ifndef NO_SDLPANGO
1353 
1354   if (fi->handle->typ == FONT_TYPE_PANGO)
1355   {
1356     snprintf(description, sizeof(description), "%s%s%s", fi->family,
1357       (text_state ^ TTF_STYLE_ITALIC ? " italic" : ""),
1358       (text_state ^ TTF_STYLE_BOLD ? " bold" : ""));
1359 
1360     pathname = (char *) "";
1361 
1362 #ifdef DEBUG
1363     printf("getfonthandle(%d) asking SDL_Pango for %s\n", desire, description);
1364 #endif
1365   }
1366 #endif
1367 */
1368 
1369 /* FIXME: Doesn't make sense; fi->handle is NULL! -bjk 2007.07.17
1370   if (fi->handle->typ == FONT_TYPE_TTF)
1371 */
1372   {
1373     if (!name)
1374       {
1375         name = fi->filename[text_state ^ TTF_STYLE_ITALIC];
1376         missing = text_state & TTF_STYLE_ITALIC;
1377       }
1378     if (!name)
1379       {
1380         name = fi->filename[text_state ^ TTF_STYLE_BOLD];
1381         missing = text_state & TTF_STYLE_BOLD;
1382       }
1383     if (!name)
1384       {
1385         name = fi->filename[text_state ^ (TTF_STYLE_ITALIC | TTF_STYLE_BOLD)];
1386         missing = text_state & (TTF_STYLE_ITALIC | TTF_STYLE_BOLD);
1387       }
1388     if (!name)
1389       {
1390 #ifdef DEBUG
1391         printf("name is still NULL\n");
1392         fflush(stdout);
1393 #endif
1394         return (NULL);
1395       }
1396 
1397     pathname = alloca(strlen(fi->directory) + 1 + strlen(name) + 1);
1398     sprintf(pathname, "%s/%s", fi->directory, name);
1399 
1400     strcpy(description, "");
1401   }
1402 
1403   fi->handle = TuxPaint_Font_OpenFont(description, pathname, text_sizes[text_size]);
1404   // if the font doesn't load, we die -- it did load OK before though
1405 
1406   if (fi->handle == NULL)
1407     {
1408 #ifdef DEBUG
1409       printf("fi->handle is NULL!\n");
1410       fflush(stdout);
1411 #endif
1412       return (NULL);
1413     }
1414 
1415   if (fi->handle->typ == FONT_TYPE_TTF)
1416     {
1417       if (fi->handle->ttf_font == NULL)
1418         {
1419 #ifdef DEBUG
1420           printf("fi->handle->ttf_font is NULL!\n");
1421           fflush(stdout);
1422 #endif
1423           return (NULL);
1424         }
1425 
1426 #ifdef DEBUG
1427       printf("calling TTF_SetFontStyle(0x%x)\n", missing);
1428       fflush(stdout);
1429 #endif
1430 
1431       TTF_SetFontStyle(fi->handle->ttf_font, missing);
1432     }
1433 
1434 #ifndef NO_SDLPANGO
1435   if (fi->handle->typ == FONT_TYPE_PANGO)
1436     printf("It's a Pango context...\n");
1437 #endif
1438 
1439   return fi->handle;
1440 }
1441 
1442 
1443 // backdoor into qsort operations, so we don't have to do work again
1444 static int was_bad_font;
1445 
1446 // see if two font surfaces are the same
do_surfcmp(const SDL_Surface * const * const v1,const SDL_Surface * const * const v2)1447 static int do_surfcmp(const SDL_Surface * const *const v1, const SDL_Surface * const *const v2)
1448 {
1449   const SDL_Surface *const s1 = *v1;
1450   const SDL_Surface *const s2 = *v2;
1451   int width;
1452   int cmp;
1453   int i;
1454 
1455   if (s1 == s2)
1456     {
1457       fprintf(stderr, "s1==s2?\n");
1458       return 0;
1459     }
1460   if (!s1 || !s2 || !s1->w || !s2->w || !s1->h || !s2->h || !s1->format || !s2->format)
1461     {
1462       was_bad_font = 1;
1463       return 0;
1464     }
1465   if (s1->format->BytesPerPixel != s2->format->BytesPerPixel)
1466     {
1467       // something really strange and bad happened
1468       was_bad_font = 1;
1469       return s1->format->BytesPerPixel - s2->format->BytesPerPixel;
1470     }
1471 
1472 
1473   if (s1->w != s2->w)
1474     return s1->w - s2->w;
1475   if (s1->h != s2->h)
1476     return s1->h - s2->h;
1477 
1478   {
1479     const char *const c1 = (char *const)s1->pixels;
1480     const char *const c2 = (char *const)s2->pixels;
1481 
1482     width = s1->format->BytesPerPixel * s1->w;
1483     if (width == s1->pitch)
1484       return memcmp(c1, c2, width * s1->h);
1485     cmp = 0;
1486     i = s1->h;
1487     while (i--)
1488       {
1489         cmp = memcmp(c1 + i * s1->pitch, c2 + i * s2->pitch, width);
1490         if (cmp)
1491           break;
1492       }
1493   }
1494 
1495   return cmp;
1496 }
1497 
1498 // see if two font surfaces are the same
surfcmp(const void * s1,const void * s2)1499 static int surfcmp(const void *s1, const void *s2)
1500 {
1501   int diff = do_surfcmp(s1, s2);
1502 
1503   if (!diff)
1504     was_bad_font = 1;
1505   return diff;
1506 }
1507 
1508 // check if the characters will render distinctly
charset_works(TuxPaint_Font * font,const char * s)1509 int charset_works(TuxPaint_Font * font, const char *s)
1510 {
1511   SDL_Color black = { 0, 0, 0, 0 };
1512 #ifndef NO_SDLPANGO
1513   SDLPango_Matrix pango_color;
1514 #endif
1515   SDL_Surface **surfs = malloc(strlen(s) * sizeof surfs[0]);
1516   unsigned count = 0;
1517   int ret = 0;
1518 
1519   while (*s)
1520     {
1521       char c[8];
1522       unsigned offset = 0;
1523       SDL_Surface *tmp_surf = NULL;
1524 
1525       do
1526         c[offset++] = *s++;
1527       while ((*s & 0xc0u) == 0x80u);    // assume safe input
1528       c[offset++] = '\0';
1529 
1530 #ifndef NO_SDLPANGO
1531       if (font->typ == FONT_TYPE_PANGO)
1532         {
1533           sdl_color_to_pango_color(black, &pango_color);
1534           SDLPango_SetDefaultColor(font->pango_context, &pango_color);
1535           SDLPango_SetText(font->pango_context, c, -1);
1536           tmp_surf = SDLPango_CreateSurfaceDraw(font->pango_context);
1537         }
1538 #endif
1539 
1540 /* FIXME: Should the following be in an "#else" block!? -bjk 2009.06.01 */
1541       if (font->typ == FONT_TYPE_TTF)
1542         {
1543           tmp_surf = TTF_RenderUTF8_Blended(font->ttf_font, c, black);
1544         }
1545 
1546       if (!tmp_surf)
1547         {
1548 #if 0
1549 // THREADED_FONTS
1550           printf("could not render \"%s\" font\n", TTF_FontFaceFamilyName(font));
1551 #endif
1552           goto out;
1553         }
1554       surfs[count++] = tmp_surf;
1555     }
1556   was_bad_font = 0;
1557   qsort(surfs, count, sizeof surfs[0], surfcmp);
1558   ret = !was_bad_font;
1559 out:
1560   while (count--)
1561     {
1562       if (surfs[count] == NULL)
1563         fprintf(stderr, "TRYING TO RE-FREE!");
1564       else
1565         {
1566           SDL_FreeSurface(surfs[count]);
1567           surfs[count] = NULL;
1568         }
1569     }
1570   free(surfs);
1571   return ret;
1572 }
1573 
TuxPaint_Font_FontHeight(TuxPaint_Font * tpf)1574 int TuxPaint_Font_FontHeight(TuxPaint_Font * tpf)
1575 {
1576   if (tpf == NULL)
1577     {
1578 #ifdef DEBUG
1579       printf("TuxPaint_Font_FontHeight() received NULL\n");
1580       fflush(stdout);
1581 #endif
1582       return (1);
1583     }
1584 
1585   return (tpf->height);
1586 }
1587 
TuxPaint_Font_FontFaceFamilyName(TuxPaint_Font * tpf)1588 const char *TuxPaint_Font_FontFaceFamilyName(TuxPaint_Font * tpf)
1589 {
1590   if (tpf == NULL)
1591     {
1592 #ifdef DEBUG
1593       printf("TuxPaint_Font_FontFaceFamilyName() received NULL\n");
1594       fflush(stdout);
1595 #endif
1596       return ("");
1597     }
1598 
1599 #ifndef NO_SDLPANGO
1600   if (tpf->typ == FONT_TYPE_PANGO)
1601     {
1602       (void)(tpf);
1603       /* FIXME */
1604 
1605       return ("");
1606     }
1607 #endif
1608 
1609   if (tpf->typ == FONT_TYPE_TTF)
1610     return (TTF_FontFaceFamilyName(tpf->ttf_font));
1611 
1612 #ifdef DEBUG
1613   printf("TuxPaint_Font_FontFaceFamilyName() is confused\n");
1614 #endif
1615 
1616   return ("");
1617 }
1618 
TuxPaint_Font_FontFaceStyleName(TuxPaint_Font * tpf)1619 const char *TuxPaint_Font_FontFaceStyleName(TuxPaint_Font * tpf)
1620 {
1621   if (tpf == NULL)
1622     {
1623 #ifdef DEBUG
1624       printf("TuxPaint_Font_FontFaceStyleName() received NULL\n");
1625       fflush(stdout);
1626 #endif
1627       return ("");
1628     }
1629 
1630 #ifndef NO_SDLPANGO
1631   if (tpf->typ == FONT_TYPE_PANGO)
1632     {
1633       (void)(tpf);
1634       /* FIXME */
1635 
1636       return ("");
1637     }
1638 #endif
1639 
1640   if (tpf->typ == FONT_TYPE_TTF)
1641     return (TTF_FontFaceStyleName(tpf->ttf_font));
1642 
1643 #ifdef DEBUG
1644   printf("TuxPaint_Font_FontFaceStyleName() is confused\n");
1645 #endif
1646 
1647   return ("");
1648 }
1649 
1650 
1651 #ifndef NO_SDLPANGO
1652 
sdl_color_to_pango_color(SDL_Color sdl_color,SDLPango_Matrix * pango_color)1653 void sdl_color_to_pango_color(SDL_Color sdl_color, SDLPango_Matrix * pango_color)
1654 {
1655   Uint8 pc[4][4];
1656 
1657   pc[0][0] = 0;
1658   pc[1][0] = 0;
1659   pc[2][0] = 0;
1660   pc[3][0] = 0;
1661 
1662   pc[0][1] = sdl_color.r;
1663   pc[1][1] = sdl_color.g;
1664   pc[2][1] = sdl_color.b;
1665   pc[3][1] = 255;
1666 
1667   pc[0][2] = 0;
1668   pc[1][2] = 0;
1669   pc[2][2] = 0;
1670   pc[3][2] = 0;
1671 
1672   pc[0][3] = 0;
1673   pc[1][3] = 0;
1674   pc[2][3] = 0;
1675   pc[3][3] = 0;
1676 
1677   memcpy(pango_color, pc, 16);
1678 }
1679 
1680 #endif
1681