Mercurial > repos > blastem
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/nuklear_ui/font_android.c Sun Apr 14 23:37:11 2019 -0700 @@ -0,0 +1,194 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <limits.h> +#include "../util.h" +#include "../paths.h" +#include "sfnt.h" + +typedef enum { + STATE_DEFAULT, + STATE_DECL, + STATE_COMMENT, + STATE_TAG, + STATE_PRE_ATTRIB, + STATE_ATTRIB, + STATE_PRE_VALUE, + STATE_VALUE +} parse_state; + +#define DEFAULT_WEIGHT 400 + +char *default_font_path(void) +{ + //Would probably be better to call into Java for this, but this should do for now + FILE *f = fopen("/system/etc/fonts.xml", "rb"); + if (!f) { + return NULL; + } + long size = file_size(f); + char *font_xml = malloc(size+1); + if (size != fread(font_xml, 1, size, f)) { + free(font_xml); + fclose(f); + return NULL; + } + fclose(f); + font_xml[size] = 0; + + char *last_tag = NULL, *last_attrib = NULL, *last_value = NULL; + uint8_t last_style_was_normal = 0; + char *capture_best = NULL; + char *best = NULL; + int best_weight_diff = INT_MAX; + int last_weight = INT_MAX; + parse_state state = STATE_DEFAULT; + for(char *cur = font_xml; *cur; ++cur) { + switch (state) + { + case STATE_DEFAULT: + if (*cur == '<' && cur[1]) { + cur++; + switch(*cur) + { + case '?': + state = STATE_DECL; + break; + case '!': + if (cur[1] == '-' && cur[2] == '-') { + state = STATE_COMMENT; + cur++; + } else { + debug_message("Invalid comment\n"); + cur = font_xml + size - 1; + } + break; + default: + if (capture_best) { + cur[-1] = 0; + best = strip_ws(capture_best); + capture_best = NULL; + best_weight_diff = abs(last_weight - DEFAULT_WEIGHT); + debug_message("Found candidate %s with weight %d\n", best, last_weight); + } + state = STATE_TAG; + last_tag = cur; + last_attrib = NULL; + last_value = NULL; + last_weight = INT_MAX; + break; + } + } + break; + case STATE_DECL: + if (*cur == '?' && cur[1] == '>') { + cur++; + state = STATE_DEFAULT; + } + break; + case STATE_COMMENT: + if (*cur == '-' && cur[1] == '-' && cur[2] == '>') { + cur += 2; + state = STATE_DEFAULT; + } + break; + case STATE_TAG: + if (*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r') { + *cur = 0; + state = STATE_PRE_ATTRIB; + } else if (*cur == '>') { + *cur = 0; + state = STATE_DEFAULT; + } + break; + case STATE_PRE_ATTRIB: + if (!(*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r')) { + if (*cur == '>') { + state = STATE_DEFAULT; + if (last_style_was_normal && abs(last_weight - DEFAULT_WEIGHT) < best_weight_diff) { + capture_best = cur + 1; + } else if (best && !strcmp("/family", last_tag)) { + debug_message("found family close tag, stopping search\n"); + cur = font_xml + size - 1; + } + } else { + last_attrib = cur; + state = STATE_ATTRIB; + } + } + break; + case STATE_ATTRIB: + if (*cur == '=') { + *cur = 0; + state = STATE_PRE_VALUE; + } else if (*cur == ' ' || *cur == '\t' || *cur == '\n' || *cur == '\r') { + *cur = 0; + } + break; + case STATE_PRE_VALUE: + if (*cur == '"') { + state = STATE_VALUE; + last_value = cur + 1; + } + break; + case STATE_VALUE: + if (*cur == '"') { + *cur = 0; + state = STATE_PRE_ATTRIB; + if (!strcmp("weight", last_attrib)) { + last_weight = atoi(last_value); + } else if (!strcmp("style", last_attrib)) { + last_style_was_normal = !strcmp("normal", last_value); + } + } + break; + } + } + if (best) { + best = path_append("/system/fonts", best); + } + free(font_xml); + return best; +} + +static uint8_t *try_load_font(char *path, uint32_t *size_out) +{ + debug_message("Trying to load font %s\n", path); + FILE *f = fopen(path, "rb"); + free(path); + if (!f) { + return NULL; + } + long size = file_size(f); + uint8_t *buffer = malloc(size); + if (size != fread(buffer, 1, size, f)) { + fclose(f); + return NULL; + } + fclose(f); + sfnt_container *sfnt = load_sfnt(buffer, size); + if (!sfnt) { + free(buffer); + return NULL; + } + return sfnt_flatten(sfnt->tables, size_out); +} + +uint8_t *default_font(uint32_t *size_out) +{ + char *path = default_font_path(); + if (!path) { + goto error; + } + uint8_t *ret = try_load_font(path, size_out); + if (ret) { + return ret; + } +error: + //try some likely suspects if we failed to parse fonts.xml or failed to find the indicated font + ret = try_load_font("/system/fonts/Roboto-Regular.ttf", size_out); + if (!ret) { + ret = try_load_font("/system/fonts/DroidSans.ttf", size_out); + } + return ret; +}