#include "font.h" #include #include static bool font_descriptor_contains_character(font_descriptor_t **descriptor, uint32_t c); uint32_t font_get_real_char(char *text, uint16_t *bytes) { *bytes = 1; uint8_t first_byte_offset = 0; if ((*text & 0xC0) == 0xC0 && (*text & 0x20) == 0) { first_byte_offset = 3; *bytes = 2; } if ((*text & 0xE0) == 0xE0 && (*text & 0x10) == 0) { first_byte_offset = 4; *bytes = 3; } if ((*text & 0xF0) == 0xF0 && (*text & 0x8) == 0) { first_byte_offset = 5; *bytes = 4; } uint32_t result = ((*text) << first_byte_offset) >> first_byte_offset; for (int i = 1; i < *bytes; i++) { result <<= 6; char current = *(text + i); if ((current & 0x80) != 0x80 || (current & 0x40)) { // malformed or no unicode, abort *bytes = 1; return *text; } result |= ((current >> 2) << 2); } return result; } font_t font_create(font_descriptor_t descriptor) { font_t font = { .font = descriptor, .size = descriptor.height, .char_spacing = 0, .line_spacing = 0, }; return font; } size2d_t font_measure_text(font_t *font, char *text) { size2d_t size = {.x = 0, .y = font->size}; double scale = (double)font->size / font->font.height; size_t len = strlen(text); for (int i = 0; i < len && *text != '\0'; i++) { uint16_t bytes; uint32_t c = font_get_real_char(text, &bytes); text += bytes; font_character_t character = font_get_character(font, c); size.x += character.width * scale; } return size; } font_character_t font_get_character(font_t *font, uint32_t c) { font_descriptor_t *descriptor = &font->font; if (!font_descriptor_contains_character(&descriptor, c)) { return font_get_character(font, font->font.default_char); } uint32_t index = c - descriptor->first_char; uint16_t width = descriptor->max_width; if (descriptor->widths != NULL) { width = descriptor->widths[index]; } uint32_t one_char_width = (width + sizeof(font_bits_t) * 8 - 1) / (sizeof(font_bits_t) * 8); uint32_t offset = (one_char_width * descriptor->height) * (index); if (descriptor->offsets != NULL) { offset = descriptor->offsets[index]; } font_character_t character = { .width = width, .bits = descriptor->bits + offset}; return character; } static bool font_descriptor_contains_character(font_descriptor_t **descriptor, uint32_t c) { if (*descriptor == NULL) { return false; } bool contains = c >= (*descriptor)->first_char && c - (*descriptor)->first_char < (*descriptor)->chars_count; if (!contains) { *descriptor = (*descriptor)->font_next_part; return font_descriptor_contains_character(descriptor, c); } return true; } bool font_contains_character(font_t *font, uint32_t c){ font_descriptor_t *descriptor = &font->font; return font_descriptor_contains_character(&descriptor, c); } uint16_t font_fit_ellipsis(font_t *font, size2d_t size, char *text, char *ellipsis) { uint16_t ellipsis_width = font_measure_text(font, ellipsis).x; size.x -= ellipsis_width; return font_fit_cut(font, size, text); } uint16_t font_fit_cut(font_t *font, size2d_t size, char *text) { size_t len = strlen(text); uint16_t x_size = 0; double scale = (double)font->size / font->font.height; for (int i = 0; i < len; i++) { font_character_t character = font_get_character(font, text[i]); x_size += character.width * scale; if (x_size > size.x) { return i; } } return 0; }