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
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 }