Blame | Last modification | View Log | RSS feed
#include "global.h"#include "lib/fbconsole/fbconsole.h"#include "interface/console/console.h"#include "interface/framebuffer/framebuffer.h"#include "interface/textrenderer/textrenderer.h"#include "sys/util.h"static const uint32_t fbconsole_color[][8] ={{0x000000, 0xaa0000, 0x00aa00, 0xaa5500, 0x0000aa, 0xaa00aa, 0x00aaaa, 0xaaaaaa},{0x555555, 0xff5555, 0x55ff55, 0xffff55, 0x5555ff, 0xff55ff, 0x55ffff, 0xffffff},};static void fbconsole_dirty(const struct console_instance* instance, int x, int y, int w, int h){struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;if (!state->dirty){state->dirty = true;state->dirty_xs = x;state->dirty_xe = x + w;state->dirty_ys = y;state->dirty_ye = y + h;return;}if (x < state->dirty_xs) state->dirty_xs = x;if (x + w > state->dirty_xe) state->dirty_xe = x + w;if (y < state->dirty_ys) state->dirty_ys = y;if (y + h > state->dirty_ye) state->dirty_ye = y + h;}static void fbconsole_renderchar(const struct console_instance* instance, int x, int y, char c){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;framebuffer_fill(data->fb, data->x + x * state->cwidth, data->y + y * state->cheight, state->cwidth,state->cheight, data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);textrenderer_render_char(data->renderer, data->fb, data->x + x * state->cwidth,data->y + y * state->cheight, state->fgcolor, c);fbconsole_dirty(instance, x, y, 1, 1);}static void fbconsole_erase_range(const struct console_instance* instance, int x, int y, int w, int h){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;framebuffer_fill(data->fb, data->x + x * state->cwidth, data->y + y * state->cheight, w * state->cwidth,h * state->cheight, data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);fbconsole_dirty(instance, x, y, w, h);}static void fbconsole_clear(const struct console_instance* instance){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;fbconsole_erase_range(instance, 0, 0, data->w, data->h);}static void fbconsole_scroll(const struct console_instance* instance, int lines){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;if (lines >= data->h || -lines >= data->h) return fbconsole_clear(instance);if (lines > 0){framebuffer_blit(data->fb, data->x, data->y + lines * state->cheight, data->fb, data->x, data->y,data->w * state->cwidth, (data->h - lines) * state->cheight, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);framebuffer_fill(data->fb, data->x, data->y + (data->h - lines) * state->cheight, data->w * state->cwidth,state->cheight * lines, data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);}else{int y;for (y = 0; y < data->h + lines; y++)framebuffer_blit(data->fb, data->x, data->y + y * state->cheight,data->fb, data->x, data->y + (y - lines) * state->cheight,data->w * state->cwidth, state->cheight, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);framebuffer_fill(data->fb, data->x, data->y, data->w * state->cwidth, state->cheight * -lines,data->fb->format, state->bgcolor, FRAMEBUFFER_CONVERSION_QUALITY_CLIP);}fbconsole_dirty(instance, 0, 0, data->w, data->h);}static void fbconsole_process_sgr(const struct console_instance* instance, int sgr){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;switch (sgr){case 0:state->bgcolcode = 0;state->fgcolcode = 7;state->intensity = 0;state->inverse = 0;break;case 1:state->intensity = 1;break;case 7:state->inverse = 1;break;case 21:state->intensity = 0;break;case 27:state->inverse = 0;break;case 30 ... 37:state->fgcolcode = sgr - 30;break;case 40 ... 47:state->bgcolcode = sgr - 40;break;default:break;}state->fgcolor = framebuffer_color_from_rgb888_be(data->fb->format, fbconsole_color[state->intensity][state->fgcolcode]);state->bgcolor = framebuffer_color_from_rgb888_be(data->fb->format, fbconsole_color[0][state->bgcolcode]);if (state->inverse){uint32_t tmp = state->fgcolor;state->fgcolor = state->bgcolor;state->bgcolor = tmp;}}static void fbconsole_init(const struct console_instance* instance){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;textrenderer_init(data->renderer);state->cwidth = textrenderer_get_max_width(data->renderer);state->cheight = textrenderer_get_line_height(data->renderer);state->cpos_x = 0;state->cpos_y = 0;state->dirty = false;state->meta = false;fbconsole_process_sgr(instance, 0);fbconsole_clear(instance);}static int fbconsole_get_width(const struct console_instance* instance){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;return data->w;}static int fbconsole_get_height(const struct console_instance* instance){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;return data->h;}static void fbconsole_putc(const struct console_instance* instance, char c){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;if (c == 0x1b){state->escape = true;state->meta = false;return;}if (state->meta)switch (c){case '0' ... '9':if (state->secondarg){state->arg2_present = true;state->meta_arg2 = state->meta_arg2 * 10 + c - '0';}else{state->arg1_present = true;state->meta_arg1 = state->meta_arg1 * 10 + c - '0';}return;case ';':if (state->secondarg) state->badmeta = true;else state->secondarg = true;return;case 'A' ... 'Z':case 'a' ... 'z':state->meta = false;if (state->badmeta) return;if (!state->arg1_present) state->meta_arg1 = 1;if (!state->arg2_present) state->meta_arg2 = 1;switch (c){case 'A':state->cpos_y = MAX(0, state->cpos_y - state->meta_arg1 + 1);break;case 'B':state->cpos_y = MIN(data->h, state->cpos_y + state->meta_arg1 - 1);break;case 'C':state->cpos_x = MAX(0, state->cpos_x - state->meta_arg1 + 1);break;case 'D':state->cpos_x = MIN(data->w, state->cpos_x + state->meta_arg1 - 1);break;case 'E':state->cpos_x = 0;state->cpos_y = MIN(data->h, state->cpos_y + state->meta_arg1 - 1);break;case 'F':state->cpos_x = 0;state->cpos_y = MAX(0, state->cpos_y - state->meta_arg1 + 1);break;case 'G':state->cpos_x = MAX(0, MIN(data->w, state->meta_arg1 - 1));break;case 'H':case 'f':state->cpos_x = MAX(0, MIN(data->w, state->meta_arg2 - 1));state->cpos_y = MAX(0, MIN(data->h, state->meta_arg1 - 1));break;case 'J':if (!state->arg1_present) state->meta_arg1 = 0;switch (state->meta_arg1){case 0:if (state->cpos_y < data->h - 1)fbconsole_erase_range(instance, 0, state->cpos_y + 1, data->w, data->h - state->cpos_y - 1);if (state->cpos_x < data->w)fbconsole_erase_range(instance, state->cpos_x, state->cpos_y, data->w - state->cpos_x, 1);break;case 1:if (state->cpos_y) fbconsole_erase_range(instance, 0, 0, data->w, state->cpos_y);if (state->cpos_x) fbconsole_erase_range(instance, 0, state->cpos_y, state->cpos_x, 1);break;case 2:fbconsole_clear(instance);break;default:break;}break;case 'K':if (!state->arg1_present) state->meta_arg1 = 0;switch (state->meta_arg1){case 0:if (state->cpos_x < data->w)fbconsole_erase_range(instance, state->cpos_x, state->cpos_y, data->w - state->cpos_x, 1);break;case 1:if (state->cpos_x) fbconsole_erase_range(instance, 0, state->cpos_y, state->cpos_x, 1);break;case 2:if (state->cpos_y < data->h)fbconsole_erase_range(instance, 0, state->cpos_y, data->w, 1);break;default:break;}break;case 'S':fbconsole_scroll(instance, state->meta_arg1);break;case 'T':fbconsole_scroll(instance, -state->meta_arg1);break;case 'm':if (!state->arg1_present) state->meta_arg1 = 0;fbconsole_process_sgr(instance, state->meta_arg1);if (state->arg2_present) fbconsole_process_sgr(instance, state->meta_arg2);break;default:break;}return;default:state->meta = false;break;}if (state->escape && c == '['){state->escape = false;state->meta = true;state->badmeta = false;state->secondarg = false;state->arg1_present = false;state->arg2_present = false;state->meta_arg1 = 0;state->meta_arg2 = 0;return;}state->escape = false;switch (c){case 0x08: // backspaceif (!state->cpos_x) break;state->cpos_x--;fbconsole_renderchar(instance, state->cpos_x, state->cpos_y, ' ');break;case 0x0a: // line feedstate->cpos_x = 0;state->cpos_y++;break;case 0x0c: // form feedstate->cpos_x = 0;state->cpos_y = 0;fbconsole_clear(instance);break;case 0x0d: // carriage returnstate->cpos_x = 0;break;default:if (state->cpos_x >= data->w){state->cpos_x = 0;state->cpos_y++;}if (state->cpos_y >= data->h){fbconsole_scroll(instance, state->cpos_y - data->h + 1);state->cpos_y = data->h - 1;}fbconsole_renderchar(instance, state->cpos_x++, state->cpos_y, c);break;}}static void fbconsole_puts(const struct console_instance* instance, const char* str){while (*str) fbconsole_putc(instance, *str++);}static void fbconsole_write(const struct console_instance* instance, const char* buf, int len){while (len--) fbconsole_putc(instance, *buf++);}static void fbconsole_flush(const struct console_instance* instance){struct fbconsole_config* data = (struct fbconsole_config*)instance->driver_config;struct fbconsole_state* state = (struct fbconsole_state*)instance->driver_state;if (!state->dirty) return;framebuffer_update(data->fb, data->x + state->dirty_xs * state->cwidth, data->y + state->dirty_ys * state->cheight,(state->dirty_xe - state->dirty_xs) * state->cwidth, (state->dirty_ye - state->dirty_ys) * state->cheight);state->dirty = false;}const struct console_driver fbconsole_driver ={.init = fbconsole_init,.get_width = fbconsole_get_width,.get_height = fbconsole_get_height,.putc = fbconsole_putc,.puts = fbconsole_puts,.write = fbconsole_write,.flush = fbconsole_flush,};