summaryrefslogtreecommitdiff
path: root/framebuffer/font_internal.c
diff options
context:
space:
mode:
Diffstat (limited to 'framebuffer/font_internal.c')
-rw-r--r--framebuffer/font_internal.c400
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