From d542e7597598f84229f40fe1062c80b4ec6e45b3 Mon Sep 17 00:00:00 2001 From: TOKITA Hiroshi Date: Wed, 8 Nov 2023 12:01:59 +0900 Subject: [PATCH] fb: cfb: Fix CFB_FONT_MSB_FIRST font rendering I broke the rendering of the CFB_FONT_MSB_FIRST font in the previously committed #53796. I will correct the entire font rendering process to make it easier to remove the restriction that the vertical size of the font must be a multiple of 8. Signed-off-by: TOKITA Hiroshi --- subsys/fb/cfb.c | 108 ++++++++++++++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 41 deletions(-) diff --git a/subsys/fb/cfb.c b/subsys/fb/cfb.c index 379066e3b53..569d610cbeb 100644 --- a/subsys/fb/cfb.c +++ b/subsys/fb/cfb.c @@ -7,6 +7,7 @@ #include #include #include +#include #define LOG_LEVEL CONFIG_CFB_LOG_LEVEL #include @@ -15,6 +16,9 @@ LOG_MODULE_REGISTER(cfb); STRUCT_SECTION_START_EXTERN(cfb_font); STRUCT_SECTION_END_EXTERN(cfb_font); +#define LSB_BIT_MASK(x) BIT_MASK(x) +#define MSB_BIT_MASK(x) (BIT_MASK(x) << (8 - x)) + static inline uint8_t byte_reverse(uint8_t b) { b = (b & 0xf0) >> 4 | (b & 0x0f) << 4; @@ -92,8 +96,9 @@ static uint8_t draw_char_vtmono(const struct char_framebuffer *fb, bool draw_bg) { const struct cfb_font *fptr = &(fb->fonts[fb->font_idx]); - const bool need_reverse = (((fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0) - != ((fptr->caps & CFB_FONT_MSB_FIRST) != 0)); + const bool font_is_msbfirst = ((fptr->caps & CFB_FONT_MSB_FIRST) != 0); + const bool need_reverse = + (((fb->screen_info & SCREEN_INFO_MONO_MSB_FIRST) != 0) != font_is_msbfirst); uint8_t *glyph_ptr; if (c < fptr->first_char || c > fptr->last_char) { @@ -108,7 +113,7 @@ static uint8_t draw_char_vtmono(const struct char_framebuffer *fb, for (size_t g_x = 0; g_x < fptr->width; g_x++) { const int16_t fb_x = x + g_x; - for (size_t g_y = 0; g_y < fptr->height; g_y++) { + for (size_t g_y = 0; g_y < fptr->height;) { /* * Process glyph rendering in the y direction * by separating per 8-line boundaries. @@ -117,66 +122,87 @@ static uint8_t draw_char_vtmono(const struct char_framebuffer *fb, const int16_t fb_y = y + g_y; const size_t fb_index = (fb_y / 8U) * fb->x_res + fb_x; const size_t offset = y % 8; + const uint8_t bottom_lines = ((offset + fptr->height) % 8); uint8_t bg_mask; uint8_t byte; + uint8_t next_byte; if (fb_x < 0 || fb->x_res <= fb_x || fb_y < 0 || fb->y_res <= fb_y) { + g_y++; continue; } - byte = get_glyph_byte(glyph_ptr, fptr, g_x, g_y / 8); - - if (offset == 0) { + if (offset == 0 || g_y == 0) { /* - * The start row is on an 8-line boundary. - * Therefore, it can set the value directly. + * The case of drawing the first line of the glyphs or + * starting to draw with a tile-aligned position case. + * In this case, no character is above it. + * So, we process assume that nothing is drawn above. */ - bg_mask = 0; - g_y += 7; - } else if (g_y == 0) { - /* - * If the starting row is not on the 8-line boundary, - * shift the glyph to the starting line, and create a mask - * from the 8-line boundary to the starting line. - */ - byte = byte << offset; - bg_mask = BIT_MASK(offset); - g_y += (7 - offset); + byte = 0; + next_byte = get_glyph_byte(glyph_ptr, fptr, g_x, g_y / 8); } else { + byte = get_glyph_byte(glyph_ptr, fptr, g_x, g_y / 8); + next_byte = get_glyph_byte(glyph_ptr, fptr, g_x, (g_y + 8) / 8); + } + + if (font_is_msbfirst) { /* - * After the starting row, read and concatenate the next 8-rows - * glyph and clip to the 8-line boundary and write 8-lines - * at the time. - * Create a mask to prevent overwriting the drawing contents - * after the end row. + * Extract the necessary 8 bits from the combined 2 tiles of glyphs. */ - const size_t lines = ((fptr->height - g_y) < 8) ? offset : 8; + byte = ((byte << 8) | next_byte) >> (offset); - if (lines == 8) { - uint16_t byte2 = byte; - - byte2 |= (get_glyph_byte(glyph_ptr, fptr, g_x, - (g_y + 8) / 8)) - << 8; - byte = (byte2 >> (8 - offset)) & BIT_MASK(lines); + if (g_y == 0) { + /* + * Create a mask that does not draw offset white space. + */ + bg_mask = BIT_MASK(8 - offset); } else { - byte = (byte >> (8 - offset)) & BIT_MASK(lines); + /* + * The drawing of the second line onwards + * is aligned with the tile, so it draws all the bits. + */ + bg_mask = 0xFF; } + } else { + byte = ((next_byte << 8) | byte) >> (8 - offset); + if (g_y == 0) { + bg_mask = BIT_MASK(8 - offset) << offset; + } else { + bg_mask = 0xFF; + } + } - bg_mask = (BIT_MASK(8 - lines) << (lines)) & 0xFF; - g_y += (lines - 1); + /* + * Clip the bottom margin to protect existing draw contents. + */ + if (((fptr->height - g_y) < 8) && (bottom_lines != 0)) { + const uint8_t clip = font_is_msbfirst ? MSB_BIT_MASK(bottom_lines) + : LSB_BIT_MASK(bottom_lines); + + bg_mask &= clip; + byte &= clip; + } + + if (draw_bg) { + if (need_reverse) { + bg_mask = byte_reverse(bg_mask); + } + fb->buf[fb_index] &= ~bg_mask; } if (need_reverse) { byte = byte_reverse(byte); - bg_mask = byte_reverse(bg_mask); } - - if (draw_bg) { - fb->buf[fb_index] &= bg_mask; - } - fb->buf[fb_index] |= byte; + + if (g_y == 0) { + g_y += (8 - offset); + } else if ((fptr->height - g_y) >= 8) { + g_y += 8; + } else { + g_y += bottom_lines; + } } }