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