comparison nuklear_ui/font_win.c @ 1527:4f6e8acd7b6a nuklear_ui

Added support for TTC and dfont format true type fonts. More robust font selection on Windows
author Michael Pavone <pavone@retrodev.com>
date Tue, 06 Mar 2018 21:27:12 -0800
parents b96f9fae757f
children 982c5327dfcc
comparison
equal deleted inserted replaced
1526:9bea1a199f15 1527:4f6e8acd7b6a
1 #include <windows.h> 1 #include <windows.h>
2 #include <shlobj.h> 2 #include <shlobj.h>
3 #include <string.h>
3 #include "../paths.h" 4 #include "../paths.h"
4 #include "../util.h" 5 #include "../util.h"
6 #include "sfnt.h"
5 7
6 char *default_font_path(void) 8 uint8_t *default_font(uint32_t *size_out)
7 { 9 {
10 static const char *thin[] = {"Thin", NULL};
11 static const char *extra_light[] = {"ExtraLight", "UltraLight", NULL};
12 static const char *light[] = {"Light", NULL};
13 static const char *regular[] = {"Regular", "Normal", "Book", NULL};
14 static const char *medium[] = {"Medium", NULL};
15 static const char *semi_bold[] = {"SemiBold", "DemiBold", NULL};
16 static const char *bold[] = {"Bold", NULL};
17 static const char *extra_bold[] = {"ExtraBold", "UltraBold", NULL};
18 static const char *heavy[] = {"Heavy", "Black", NULL};
19 static const char **weight_to_subfamilies[] = {
20 NULL,
21 thin,
22 extra_light,
23 light,
24 regular,
25 medium,
26 semi_bold,
27 bold,
28 extra_bold,
29 heavy
30 };
31
8 NONCLIENTMETRICSA metrics = { 32 NONCLIENTMETRICSA metrics = {
9 .cbSize = sizeof(metrics) 33 .cbSize = sizeof(metrics)
10 }; 34 };
11 char *pref_name = NULL; 35 char *pref_name = NULL, *pref_prefix = NULL;
36 const char **pref_sub_families;
12 if (SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) { 37 if (SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(metrics), &metrics, 0)) {
13 pref_name = metrics.lfCaptionFont.lfFaceName; 38 pref_name = metrics.lfMenuFont.lfFaceName;
39 int32_t weight = metrics.lfMenuFont.lfWeight / 100;
40 if (weight < 1 || weight > 9) {
41 weight = 4;
42 }
43 printf("Preferred family: %s, weight: %d\n", pref_name, weight);
44 pref_sub_families = weight_to_subfamilies[weight];
14 } 45 }
46 if (pref_name) {
47 uint32_t prefix_len = 0;
48 while (pref_name[prefix_len] && pref_name[prefix_len] != ' ')
49 {
50 prefix_len++;
51 }
52 pref_prefix = malloc(prefix_len + 1);
53 memcpy(pref_prefix, pref_name, prefix_len);
54 pref_prefix[prefix_len] = 0;
55 }
56 sfnt_table *selected = NULL;
15 char windows[MAX_PATH]; 57 char windows[MAX_PATH];
16 SHGetFolderPathA(NULL, CSIDL_WINDOWS, NULL, 0, windows); 58 SHGetFolderPathA(NULL, CSIDL_WINDOWS, NULL, 0, windows);
17 char *fonts = path_append(windows, "Fonts"); 59 char *fonts = path_append(windows, "Fonts");
18 size_t num_entries; 60 size_t num_entries;
19 char *preferred = NULL, *tahoma = NULL, *arial = NULL; 61 char *tahoma = NULL, *arial = NULL;
20 dir_entry *entries = get_dir_list(fonts, &num_entries); 62 dir_entry *entries = get_dir_list(fonts, &num_entries);
63 char *path = NULL;
21 for (size_t i = 0; i < num_entries; i++) 64 for (size_t i = 0; i < num_entries; i++)
22 { 65 {
23 if (entries[i].is_dir) { 66 if (entries[i].is_dir) {
24 continue; 67 continue;
25 } 68 }
26 char *ext = path_extension(entries[i].name); 69 char *ext = path_extension(entries[i].name);
27 if (!ext || strcasecmp(ext, "ttf")) { 70 if (!ext || (strcasecmp(ext, "ttf") && strcasecmp(ext, "ttc") && strcasecmp(ext, "dfont"))) {
28 //not a truetype font, ignore 71 //not a truetype font, ignore
29 free(ext); 72 free(ext);
30 continue; 73 continue;
31 } 74 }
32 free(ext); 75 free(ext);
33 char *base = basename_no_extension(entries[i].name); 76 char *base = basename_no_extension(entries[i].name);
34 if (!strcasecmp(base, pref_name)) { 77 printf("basename: %s\n", base);
35 preferred = entries[i].name; 78 if (pref_prefix && !strncasecmp(base, pref_prefix, 6)) {
79 path = path_append(fonts, entries[i].name);
80 FILE *f = fopen(path, "rb");
81 if (f)
82 {
83 long font_size = file_size(f);
84 uint8_t *blob = malloc(font_size);
85 if (font_size == fread(blob, 1, font_size, f))
86 {
87 sfnt_container *sfnt = load_sfnt(blob, font_size);
88 if (sfnt) {
89 selected = sfnt_subfamily_by_names(sfnt, pref_sub_families);
90 if (!selected) {
91 sfnt_free(sfnt);
92 }
93 } else {
94 free(blob);
95 }
96 }
97 fclose(f);
98 }
99 free(path);
36 free(base); 100 free(base);
37 break; 101 if (selected) {
102 printf("Found preferred font in %s\n", entries[i].name);
103 break;
104 }
38 } else if (!strcasecmp(base, "tahoma")) { 105 } else if (!strcasecmp(base, "tahoma")) {
39 tahoma = entries[i].name; 106 tahoma = entries[i].name;
40 } else if (!strcasecmp(base, "arial")) { 107 } else if (!strcasecmp(base, "arial")) {
41 arial = entries[i].name; 108 arial = entries[i].name;
42 } 109 }
43 free(base); 110 free(base);
44 } 111 }
45 char *path = NULL; 112 if (!selected) {
46 if (preferred) { 113 path = NULL;
47 path = path_append(fonts, preferred); 114 if (tahoma) {
48 } else if(tahoma) { 115 path = path_append(fonts, tahoma);
49 path = path_append(fonts, tahoma); 116 } else if (arial) {
50 } else if(arial) { 117 path = path_append(fonts, arial);
51 path = path_append(fonts, arial); 118 }
119 if (path) {
120 FILE *f = fopen(path, "rb");
121 if (f)
122 {
123 long font_size = file_size(f);
124 uint8_t *blob = malloc(font_size);
125 if (font_size == fread(blob, 1, font_size, f))
126 {
127 sfnt_container *sfnt = load_sfnt(blob, font_size);
128 if (sfnt) {
129 selected = sfnt->tables;
130 } else {
131 free(blob);
132 }
133 }
134 fclose(f);
135 }
136 free(path);
137 }
52 } 138 }
53 free(fonts); 139 free(fonts);
54 free_dir_list(entries, num_entries); 140 free_dir_list(entries, num_entries);
55 return path; 141 if (selected) {
142 return sfnt_flatten(selected, size_out);
143 }
144 return NULL;
56 } 145 }