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 <tokita.hiroshi@gmail.com>
This commit is contained in:
TOKITA Hiroshi 2023-11-08 12:01:59 +09:00 committed by Anas Nashif
parent 06086ce771
commit d542e75975

View File

@ -7,6 +7,7 @@
#include <zephyr/kernel.h>
#include <string.h>
#include <zephyr/display/cfb.h>
#include <zephyr/sys/byteorder.h>
#define LOG_LEVEL CONFIG_CFB_LOG_LEVEL
#include <zephyr/logging/log.h>
@ -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;
}
}
}