diff options
Diffstat (limited to 'framebuffer/font_internal.c')
-rw-r--r-- | framebuffer/font_internal.c | 400 |
1 files changed, 349 insertions, 51 deletions
diff --git a/framebuffer/font_internal.c b/framebuffer/font_internal.c index dc1b35820..9b850d5c8 100644 --- a/framebuffer/font_internal.c +++ b/framebuffer/font_internal.c @@ -19,16 +19,170 @@ #include <inttypes.h> #include <string.h> - #include <assert.h> -#include "css/css.h" -#include "render/font.h" + #include "utils/nsoption.h" #include "utils/utf8.h" +#include "desktop/gui.h" +#include "css/css.h" +#include "render/font.h" #include "framebuffer/gui.h" #include "framebuffer/font.h" +#include <font-ns-sans.h> + +#define GLYPH_LEN 16 + +uint8_t code_point[GLYPH_LEN]; +uint8_t glyph_x2[GLYPH_LEN * 4]; + +#define SEVEN_SET ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | \ + (1 << 4) | (1 << 5) | (1 << 6)) + +#define THREE_SSS ((1 << 0) | (1 << 1) | (1 << 2)) +#define THREE_S_S ((1 << 0) | (1 << 2)) +#define THREE__SS ((1 << 0) | (1 << 1) ) +#define THREE_SS_ ( (1 << 1) | (1 << 2)) +#define THREE_S__ (1 << 2) +#define THREE__S_ (1 << 1) +#define THREE___S (1 << 0) + +uint8_t frag[16][5] = { + { THREE_SSS, + THREE_S_S, + THREE_S_S, + THREE_S_S, + THREE_SSS }, + + { THREE__S_, + THREE_SS_, + THREE__S_, + THREE__S_, + THREE_SSS }, + + { THREE_SS_, + THREE___S, + THREE__S_, + THREE_S__, + THREE_SSS }, + + { THREE_SS_, + THREE___S, + THREE_SS_, + THREE___S, + THREE_SS_ }, + + { THREE_S_S, + THREE_S_S, + THREE_SSS, + THREE___S, + THREE___S }, + + { THREE_SSS, + THREE_S__, + THREE_SSS, + THREE___S, + THREE_SSS }, + + { THREE__SS, + THREE_S__, + THREE_SSS, + THREE_S_S, + THREE_SSS }, + + { THREE_SSS, + THREE___S, + THREE__S_, + THREE__S_, + THREE__S_ }, + + { THREE_SSS, + THREE_S_S, + THREE_SSS, + THREE_S_S, + THREE_SSS }, + + { THREE_SSS, + THREE_S_S, + THREE_SSS, + THREE___S, + THREE___S }, + + { THREE__S_, + THREE_S_S, + THREE_SSS, + THREE_S_S, + THREE_S_S }, + + { THREE_SS_, + THREE_S_S, + THREE_SS_, + THREE_S_S, + THREE_SS_ }, + + { THREE__S_, + THREE_S_S, + THREE_S__, + THREE_S_S, + THREE__S_ }, + + { THREE_SS_, + THREE_S_S, + THREE_S_S, + THREE_S_S, + THREE_SS_ }, + + { THREE_SSS, + THREE_S__, + THREE_SS_, + THREE_S__, + THREE_SSS }, + + { THREE_SSS, + THREE_S__, + THREE_SS_, + THREE_S__, + THREE_S__ } +}; + +static uint8_t * get_codepoint(uint32_t id, bool italic) +{ + int shift = 0; + int l; + int r; + + if (!italic) + shift = 1; + + l = (id >> 12); + r = 0xf & (id >> 8); + + code_point[ 0] = SEVEN_SET << shift; + + code_point[ 2] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift); + code_point[ 3] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift); + code_point[ 4] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift); + code_point[ 5] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift); + code_point[ 6] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift); + + shift = 1; + + l = 0xf & (id >> 4); + r = 0xf & id; + + code_point[ 8] = (frag[l][0] << (4 + shift)) | (frag[r][0] << shift); + code_point[ 9] = (frag[l][1] << (4 + shift)) | (frag[r][1] << shift); + code_point[10] = (frag[l][2] << (4 + shift)) | (frag[r][2] << shift); + code_point[11] = (frag[l][3] << (4 + shift)) | (frag[r][3] << shift); + code_point[12] = (frag[l][4] << (4 + shift)) | (frag[r][4] << shift); + + code_point[14] = SEVEN_SET << shift; + + return (uint8_t *)code_point; +} + + bool fb_font_init(void) { return true; @@ -39,36 +193,132 @@ bool fb_font_finalise(void) return true; } -const struct fb_font_desc* -fb_get_font(const plot_font_style_t *fstyle) +enum fb_font_style +fb_get_font_style(const plot_font_style_t *fstyle) +{ + enum fb_font_style style = FB_REGULAR; + + if (fstyle->weight >= 700) + style |= FB_BOLD; + if ((fstyle->flags & FONTF_ITALIC) || (fstyle->flags & FONTF_OBLIQUE)) + style |= FB_ITALIC; + + return style; +} + +int +fb_get_font_size(const plot_font_style_t *fstyle) +{ + int size = fstyle->size * 10 / + (((nsoption_int(font_min_size) * 3 + + nsoption_int(font_size)) / 4) * FONT_SIZE_SCALE); + if (size > 2) + size = 2; + else if (size <= 0) + size = 1; + + return size; +} + +/** Lookup table to scale 4 bits to 8 bits, so e.g. 0101 --> 00110011 */ +const uint8_t glyph_lut[16] = { + 0x00, 0x03, 0x0c, 0x0f, + 0x30, 0x33, 0x3c, 0x3f, + 0xc0, 0xc3, 0xcc, 0xcf, + 0xf0, 0xf3, 0xfc, 0xff +}; + +static const uint8_t * +glyph_scale_2(const uint8_t *glyph_data) +{ + const uint8_t *glyph_max = glyph_data + GLYPH_LEN; + uint8_t *pos = glyph_x2; + + do { + *pos++ = glyph_lut[*glyph_data >> 4]; + *pos++ = glyph_lut[*glyph_data & 0xf]; + *pos++ = glyph_lut[*glyph_data >> 4]; + *pos++ = glyph_lut[*glyph_data & 0xf]; + } while (++glyph_data < glyph_max); + + return glyph_x2; +} + +const uint8_t * +fb_get_glyph(uint32_t ucs4, enum fb_font_style style, int scale) { - if (fstyle->weight >= 700) { - if ((fstyle->flags & FONTF_ITALIC) || - (fstyle->flags & FONTF_OBLIQUE)) { - return &font_italic_bold; - } else { - return &font_bold; + const uint8_t *glyph_data; + unsigned int section; + unsigned int offset; + uint16_t g_offset; + + /* Internal font has no glyphs beyond U+FFFF and there isn't + * space to render a >4 digit codepoint; just show replacement + * character. */ + if (ucs4 > 0xffff) + ucs4 = 0xfffd; + + switch (style) { + case FB_BOLD_ITALIC: + section = fb_bold_italic_section_table[ucs4 / 256]; + if (section != 0 || ucs4 / 256 == 0) { + offset = section * 256 + (ucs4 & 0xff); + g_offset = fb_bold_italic_sections[offset] * 16; + if (g_offset != 0) { + glyph_data = &font_glyph_data[g_offset]; + break; + } + } + case FB_BOLD: + section = fb_bold_section_table[ucs4 / 256]; + if (section != 0 || ucs4 / 256 == 0) { + offset = section * 256 + (ucs4 & 0xff); + g_offset = fb_bold_sections[offset] * 16; + if (g_offset != 0) { + glyph_data = &font_glyph_data[g_offset]; + break; + } } - } else { - if ((fstyle->flags & FONTF_ITALIC) || - (fstyle->flags & FONTF_OBLIQUE)) { - return &font_italic; - } else { - return &font_regular; + case FB_ITALIC: + section = fb_italic_section_table[ucs4 / 256]; + if (section != 0 || ucs4 / 256 == 0) { + offset = section * 256 + (ucs4 & 0xff); + g_offset = fb_italic_sections[offset] * 16; + if (g_offset != 0) { + glyph_data = &font_glyph_data[g_offset]; + break; + } } + case FB_REGULAR: + section = fb_regular_section_table[ucs4 / 256]; + if (section != 0 || ucs4 / 256 == 0) { + offset = section * 256 + (ucs4 & 0xff); + g_offset = fb_regular_sections[offset] * 16; + if (g_offset != 0) { + glyph_data = &font_glyph_data[g_offset]; + break; + } + } + default: + glyph_data = get_codepoint(ucs4, style & FB_ITALIC); + break; } -} -utf8_convert_ret utf8_to_font_encoding(const struct fb_font_desc* font, - const char *string, - size_t len, - char **result) -{ - return utf8_to_enc(string, font->encoding, len, result); + switch (scale) { + case 1: + break; + case 2: + glyph_data = glyph_scale_2(glyph_data); + break; + default: + assert(scale >= 1 && scale <= 2); + break; + } + return glyph_data; } -utf8_convert_ret utf8_to_local_encoding(const char *string, +static nserror utf8_to_local(const char *string, size_t len, char **result) { @@ -76,28 +326,41 @@ utf8_convert_ret utf8_to_local_encoding(const char *string, } -utf8_convert_ret utf8_from_local_encoding(const char *string, +static nserror utf8_from_local(const char *string, size_t len, char **result) { *result = malloc(len + 1); if (*result == NULL) { - return UTF8_CONVERT_NOMEM; + return NSERROR_NOMEM; } memcpy(*result, string, len); (*result)[len] = '\0'; - return UTF8_CONVERT_OK; + return NSERROR_OK; } + static bool nsfont_width(const plot_font_style_t *fstyle, const char *string, size_t length, int *width) { - const struct fb_font_desc* fb_font = fb_get_font(fstyle); - *width = fb_font->width * utf8_bounded_length(string, length); + size_t nxtchr = 0; + + *width = 0; + while (nxtchr < length) { + uint32_t ucs4; + ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr); + if (codepoint_displayable(ucs4)) { + *width += FB_FONT_WIDTH; + } + + nxtchr = utf8_next(string, length, nxtchr); + } + + *width *= fb_get_font_size(fstyle); return true; } @@ -117,11 +380,26 @@ static bool nsfont_position_in_string(const plot_font_style_t *fstyle, const char *string, size_t length, int x, size_t *char_offset, int *actual_x) { - const struct fb_font_desc* fb_font = fb_get_font(fstyle); - *char_offset = (x + fb_font->width / 2) / fb_font->width; - if (*char_offset > length) - *char_offset = length; - *actual_x = *char_offset * fb_font->width; + const int width = fb_get_font_size(fstyle) * FB_FONT_WIDTH; + size_t nxtchr = 0; + int x_pos = 0; + + while (nxtchr < length) { + uint32_t ucs4; + if (abs(x_pos - x) <= (width / 2)) + break; + + ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr); + if (codepoint_displayable(ucs4)) { + x_pos += width; + } + + nxtchr = utf8_next(string, length, nxtchr); + } + + *actual_x = x_pos; + + *char_offset = nxtchr; return true; } @@ -154,26 +432,38 @@ static bool nsfont_split(const plot_font_style_t *fstyle, const char *string, size_t length, int x, size_t *char_offset, int *actual_x) { + const int width = fb_get_font_size(fstyle) * FB_FONT_WIDTH; + size_t nxtchr = 0; + int last_space_x = 0; + int last_space_idx = 0; - const struct fb_font_desc* fb_font = fb_get_font(fstyle); - int c_off = *char_offset = x / fb_font->width; - if (*char_offset > length) { - *char_offset = length; - } else { - while (*char_offset > 0) { - if (string[*char_offset] == ' ') - break; - (*char_offset)--; + *actual_x = 0; + while (nxtchr < length) { + uint32_t ucs4; + + if (string[nxtchr] == ' ') { + last_space_x = *actual_x; + last_space_idx = nxtchr; } - if (*char_offset == 0) { - *char_offset = c_off; - while (*char_offset < length && - string[*char_offset] != ' ') { - (*char_offset)++; - } + + ucs4 = utf8_to_ucs4(string + nxtchr, length - nxtchr); + if (codepoint_displayable(ucs4)) { + *actual_x += width; + } + + if (*actual_x > x && last_space_idx != 0) { + /* string has exceeded available width and we've + * found a space; return previous space */ + *actual_x = last_space_x; + *char_offset = last_space_idx; + return true; } + + nxtchr = utf8_next(string, length, nxtchr); } - *actual_x = *char_offset * fb_font->width; + + *char_offset = nxtchr; + return true; } @@ -183,6 +473,14 @@ const struct font_functions nsfont = { nsfont_split }; +static struct gui_utf8_table utf8_table = { + .utf8_to_local = utf8_to_local, + .local_to_utf8 = utf8_from_local, +}; + +struct gui_utf8_table *framebuffer_utf8_table = &utf8_table; + + /* * Local Variables: * c-basic-offset:8 |