/* * This file is part of the Trezor project, https://trezor.io/ * * Copyright (c) SatoshiLabs * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "fonts.h" #include #include #include #include #ifdef TRANSLATIONS #include "librust_fonts.h" #endif #define UNICODE_BADCHAR 0xFFFD int font_height(int font) { switch (font) { #ifdef TREZOR_FONT_NORMAL_ENABLE case FONT_NORMAL: return FONT_NORMAL_HEIGHT; #endif #ifdef TREZOR_FONT_DEMIBOLD_ENABLE case FONT_DEMIBOLD: return FONT_DEMIBOLD_HEIGHT; #endif #ifdef TREZOR_FONT_BOLD_ENABLE case FONT_BOLD: return FONT_BOLD_HEIGHT; #endif #ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE case FONT_NORMAL_UPPER: return FONT_NORMAL_UPPER_HEIGHT; #endif #ifdef TREZOR_FONT_BOLD_UPPER_ENABLE case FONT_BOLD_UPPER: return FONT_BOLD_UPPER_HEIGHT; #endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_HEIGHT; #endif #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_HEIGHT; #endif #ifdef TREZOR_FONT_SUB_ENABLE case FONT_SUB: return FONT_SUB_HEIGHT; #endif } return 0; } int font_max_height(int font) { switch (font) { #ifdef TREZOR_FONT_NORMAL_ENABLE case FONT_NORMAL: return FONT_NORMAL_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_DEMIBOLD_ENABLE case FONT_DEMIBOLD: return FONT_DEMIBOLD_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_BOLD_ENABLE case FONT_BOLD: return FONT_BOLD_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE case FONT_NORMAL_UPPER: return FONT_NORMAL_UPPER_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_BOLD_UPPER_ENABLE case FONT_BOLD_UPPER: return FONT_BOLD_UPPER_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_MAX_HEIGHT; #endif #ifdef TREZOR_FONT_SUB_ENABLE case FONT_SUB: return FONT_SUB_MAX_HEIGHT; #endif } return 0; } int font_baseline(int font) { switch (font) { #ifdef TREZOR_FONT_NORMAL_ENABLE case FONT_NORMAL: return FONT_NORMAL_BASELINE; #endif #ifdef TREZOR_FONT_DEMIBOLD_ENABLE case FONT_DEMIBOLD: return FONT_DEMIBOLD_BASELINE; #endif #ifdef TREZOR_FONT_BOLD_ENABLE case FONT_BOLD: return FONT_BOLD_BASELINE; #endif #ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE case FONT_NORMAL_UPPER: return FONT_NORMAL_UPPER_BASELINE; #endif #ifdef TREZOR_FONT_BOLD_UPPER_ENABLE case FONT_BOLD_UPPER: return FONT_BOLD_UPPER_BASELINE; #endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_BASELINE; #endif #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_BASELINE; #endif #ifdef TREZOR_FONT_SUB_ENABLE case FONT_SUB: return FONT_SUB_BASELINE; #endif } return 0; } font_glyph_iter_t font_glyph_iter_init(const int font, const uint8_t *text, const int len) { return (font_glyph_iter_t){ .font = font, .text = text, .remaining = len, }; } #define IS_UTF8_CONTINUE(c) (((c) & 0b11000000) == 0b10000000) static uint16_t next_utf8_codepoint(font_glyph_iter_t *iter) { uint16_t out; assert(iter->remaining > 0); // 1-byte UTF-8 character if (iter->text[0] < 0x7f) { out = iter->text[0]; ++iter->text; --iter->remaining; return out; } // 2-byte UTF-8 character if (iter->remaining >= 2 && ((iter->text[0] & 0b11100000) == 0b11000000) && IS_UTF8_CONTINUE(iter->text[1])) { out = (((uint16_t)iter->text[0] & 0b00011111) << 6) | (iter->text[1] & 0b00111111); iter->text += 2; iter->remaining -= 2; return out; } // 3-byte UTF-8 character if (iter->remaining >= 3 && ((iter->text[0] & 0b11110000) == 0b11100000) && IS_UTF8_CONTINUE(iter->text[1]) && IS_UTF8_CONTINUE(iter->text[2])) { out = (((uint16_t)iter->text[0] & 0b00001111) << 12) | (((uint16_t)iter->text[1] & 0b00111111) << 6) | (iter->text[2] & 0b00111111); iter->text += 3; iter->remaining -= 3; return out; } // 4-byte UTF-8 character if (iter->remaining >= 4 && ((iter->text[0] & 0b11111000) == 0b11110000) && IS_UTF8_CONTINUE(iter->text[1]) && IS_UTF8_CONTINUE(iter->text[2]) && IS_UTF8_CONTINUE(iter->text[3])) { // we use 16-bit codepoints, so we can't represent 4-byte UTF-8 characters iter->text += 4; iter->remaining -= 4; return UNICODE_BADCHAR; } ++iter->text; --iter->remaining; return UNICODE_BADCHAR; } bool font_next_glyph(font_glyph_iter_t *iter, const uint8_t **out) { if (iter->remaining <= 0) { return false; } uint16_t c = next_utf8_codepoint(iter); *out = font_get_glyph(iter->font, c); if (*out == NULL) { // should not happen but ¯\_(ツ)_/¯ return font_next_glyph(iter, out); } else { return true; } } const uint8_t *font_nonprintable_glyph(int font) { #define PASTER(s) s##_glyph_nonprintable #define NONPRINTABLE_GLYPH(s) PASTER(s) switch (font) { #ifdef TREZOR_FONT_NORMAL_ENABLE case FONT_NORMAL: return NONPRINTABLE_GLYPH(FONT_NORMAL_DATA); #endif #ifdef TREZOR_FONT_DEMIBOLD_ENABLE case FONT_DEMIBOLD: return NONPRINTABLE_GLYPH(FONT_DEMIBOLD_DATA); #endif #ifdef TREZOR_FONT_BOLD_ENABLE case FONT_BOLD: return NONPRINTABLE_GLYPH(FONT_BOLD_DATA); #endif #ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE case FONT_NORMAL_UPPER: return NONPRINTABLE_GLYPH(FONT_NORMAL_UPPER_DATA); #endif #ifdef TREZOR_FONT_BOLD_UPPER_ENABLE case FONT_BOLD_UPPER: return NONPRINTABLE_GLYPH(FONT_BOLD_UPPER_DATA); #endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return NONPRINTABLE_GLYPH(FONT_MONO_DATA); #endif #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return NONPRINTABLE_GLYPH(FONT_BIG_DATA); #endif #ifdef TREZOR_FONT_SUB_ENABLE case FONT_SUB: return NONPRINTABLE_GLYPH(FONT_SUB_DATA); #endif default: return NULL; } } const uint8_t *font_get_glyph(int font, uint16_t c) { #ifdef TRANSLATIONS // found UTF8 character // it is not hardcoded in firmware fonts, it must be extracted from the // embedded blob if (c >= 0x7F) { const uint8_t *g = get_utf8_glyph(c, font); if (g != NULL) { return g; } } #endif // printable ASCII character if (c >= ' ' && c < 0x7F) { switch (font) { #ifdef TREZOR_FONT_NORMAL_ENABLE case FONT_NORMAL: return FONT_NORMAL_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_DEMIBOLD_ENABLE case FONT_DEMIBOLD: return FONT_DEMIBOLD_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_BOLD_ENABLE case FONT_BOLD: return FONT_BOLD_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_NORMAL_UPPER_ENABLE case FONT_NORMAL_UPPER: return FONT_NORMAL_UPPER_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_BOLD_UPPER_ENABLE case FONT_BOLD_UPPER: return FONT_BOLD_UPPER_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_MONO_ENABLE case FONT_MONO: return FONT_MONO_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_BIG_ENABLE case FONT_BIG: return FONT_BIG_DATA[c - ' ']; #endif #ifdef TREZOR_FONT_SUB_ENABLE case FONT_SUB: return FONT_SUB_DATA[c - ' ']; #endif } return 0; } return font_nonprintable_glyph(font); } // compute the width of the text (in pixels) int font_text_width(int font, const char *text, int textlen) { int width = 0; // determine text length if not provided if (textlen < 0) { textlen = strlen(text); } font_glyph_iter_t iter = font_glyph_iter_init(font, (uint8_t *)text, textlen); const uint8_t *g = NULL; while (font_next_glyph(&iter, &g)) { const uint8_t adv = g[2]; // advance width += adv; } return width; }