Mercurial > repos > blastem
comparison nuklear_ui/font_android.c @ 1839:78abbabfd58d
Get Android build working again and update for SDL 2.0.7 (last version to support older versions of Android)
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sun, 14 Apr 2019 23:37:11 -0700 |
parents | |
children | 13abdc98379e c649bcc18487 |
comparison
equal
deleted
inserted
replaced
1836:601ef72cc16f | 1839:78abbabfd58d |
---|---|
1 #include <stdio.h> | |
2 #include <stdlib.h> | |
3 #include <stdint.h> | |
4 #include <limits.h> | |
5 #include "../util.h" | |
6 #include "../paths.h" | |
7 #include "sfnt.h" | |
8 | |
9 typedef enum { | |
10 STATE_DEFAULT, | |
11 STATE_DECL, | |
12 STATE_COMMENT, | |
13 STATE_TAG, | |
14 STATE_PRE_ATTRIB, | |
15 STATE_ATTRIB, | |
16 STATE_PRE_VALUE, | |
17 STATE_VALUE | |
18 } parse_state; | |
19 | |
20 #define DEFAULT_WEIGHT 400 | |
21 | |
22 char *default_font_path(void) | |
23 { | |
24 //Would probably be better to call into Java for this, but this should do for now | |
25 FILE *f = fopen("/system/etc/fonts.xml", "rb"); | |
26 if (!f) { | |
27 return NULL; | |
28 } | |
29 long size = file_size(f); | |
30 char *font_xml = malloc(size+1); | |
31 if (size != fread(font_xml, 1, size, f)) { | |
32 free(font_xml); | |
33 fclose(f); | |
34 return NULL; | |
35 } | |
36 fclose(f); | |
37 font_xml[size] = 0; | |
38 | |
39 char *last_tag = NULL, *last_attrib = NULL, *last_value = NULL; | |
40 uint8_t last_style_was_normal = 0; | |
41 char *capture_best = NULL; | |
42 char *best = NULL; | |
43 int best_weight_diff = INT_MAX; | |
44 int last_weight = INT_MAX; | |
45 parse_state state = STATE_DEFAULT; | |
46 for(char *cur = font_xml; *cur; ++cur) { | |
47 switch (state) | |
48 { | |
49 case STATE_DEFAULT: | |
50 if (*cur == '<' && cur[1]) { | |
51 cur++; | |
52 switch(*cur) | |
53 { | |
54 case '?': | |
55 state = STATE_DECL; | |
56 break; | |
57 case '!': | |
58 if (cur[1] == '-' && cur[2] == '-') { | |
59 state = STATE_COMMENT; | |
60 cur++; | |
61 } else { | |
62 debug_message("Invalid comment\n"); | |
63 cur = font_xml + size - 1; | |
64 } | |
65 break; | |
66 default: | |
67 if (capture_best) { | |
68 cur[-1] = 0; | |
69 best = strip_ws(capture_best); | |
70 capture_best = NULL; | |
71 best_weight_diff = abs(last_weight - DEFAULT_WEIGHT); | |
72 debug_message("Found candidate %s with weight %d\n", best, last_weight); | |
73 } | |
74 state = STATE_TAG; | |
75 last_tag = cur; | |
76 last_attrib = NULL; | |
77 last_value = NULL; | |
78 last_weight = INT_MAX; | |
79 break; | |
80 } | |
81 } | |
82 break; | |
83 case STATE_DECL: | |
84 if (*cur == '?' && cur[1] == '>') { | |
85 cur++; | |
86 state = STATE_DEFAULT; | |
87 } | |
88 break; | |
89 case STATE_COMMENT: | |
90 if (*cur == '-' && cur[1] == '-' && cur[2] == '>') { | |
91 cur += 2; | |
92 state = STATE_DEFAULT; | |
93 } | |
94 break; | |
95 case STATE_TAG: | |
96 if (*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r') { | |
97 *cur = 0; | |
98 state = STATE_PRE_ATTRIB; | |
99 } else if (*cur == '>') { | |
100 *cur = 0; | |
101 state = STATE_DEFAULT; | |
102 } | |
103 break; | |
104 case STATE_PRE_ATTRIB: | |
105 if (!(*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r')) { | |
106 if (*cur == '>') { | |
107 state = STATE_DEFAULT; | |
108 if (last_style_was_normal && abs(last_weight - DEFAULT_WEIGHT) < best_weight_diff) { | |
109 capture_best = cur + 1; | |
110 } else if (best && !strcmp("/family", last_tag)) { | |
111 debug_message("found family close tag, stopping search\n"); | |
112 cur = font_xml + size - 1; | |
113 } | |
114 } else { | |
115 last_attrib = cur; | |
116 state = STATE_ATTRIB; | |
117 } | |
118 } | |
119 break; | |
120 case STATE_ATTRIB: | |
121 if (*cur == '=') { | |
122 *cur = 0; | |
123 state = STATE_PRE_VALUE; | |
124 } else if (*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r') { | |
125 *cur = 0; | |
126 } | |
127 break; | |
128 case STATE_PRE_VALUE: | |
129 if (*cur == '"') { | |
130 state = STATE_VALUE; | |
131 last_value = cur + 1; | |
132 } | |
133 break; | |
134 case STATE_VALUE: | |
135 if (*cur == '"') { | |
136 *cur = 0; | |
137 state = STATE_PRE_ATTRIB; | |
138 if (!strcmp("weight", last_attrib)) { | |
139 last_weight = atoi(last_value); | |
140 } else if (!strcmp("style", last_attrib)) { | |
141 last_style_was_normal = !strcmp("normal", last_value); | |
142 } | |
143 } | |
144 break; | |
145 } | |
146 } | |
147 if (best) { | |
148 best = path_append("/system/fonts", best); | |
149 } | |
150 free(font_xml); | |
151 return best; | |
152 } | |
153 | |
154 static uint8_t *try_load_font(char *path, uint32_t *size_out) | |
155 { | |
156 debug_message("Trying to load font %s\n", path); | |
157 FILE *f = fopen(path, "rb"); | |
158 free(path); | |
159 if (!f) { | |
160 return NULL; | |
161 } | |
162 long size = file_size(f); | |
163 uint8_t *buffer = malloc(size); | |
164 if (size != fread(buffer, 1, size, f)) { | |
165 fclose(f); | |
166 return NULL; | |
167 } | |
168 fclose(f); | |
169 sfnt_container *sfnt = load_sfnt(buffer, size); | |
170 if (!sfnt) { | |
171 free(buffer); | |
172 return NULL; | |
173 } | |
174 return sfnt_flatten(sfnt->tables, size_out); | |
175 } | |
176 | |
177 uint8_t *default_font(uint32_t *size_out) | |
178 { | |
179 char *path = default_font_path(); | |
180 if (!path) { | |
181 goto error; | |
182 } | |
183 uint8_t *ret = try_load_font(path, size_out); | |
184 if (ret) { | |
185 return ret; | |
186 } | |
187 error: | |
188 //try some likely suspects if we failed to parse fonts.xml or failed to find the indicated font | |
189 ret = try_load_font("/system/fonts/Roboto-Regular.ttf", size_out); | |
190 if (!ret) { | |
191 ret = try_load_font("/system/fonts/DroidSans.ttf", size_out); | |
192 } | |
193 return ret; | |
194 } |