fbcon: add support for draw different font sizes and colors

There is requirements to have display to support different font sizes,
colors. Different font sizes are using different factors for same font
size table. Different colors include different background colors and
foreground colors

Change-Id: I7ea611a6761d06e07ddb84ef5f57b03f3e9c731c
diff --git a/dev/fbcon/fbcon.c b/dev/fbcon/fbcon.c
index 885ce87..532ec10 100644
--- a/dev/fbcon/fbcon.c
+++ b/dev/fbcon/fbcon.c
@@ -47,13 +47,30 @@
 	int y;
 };
 
+struct fb_color {
+	uint32_t fg;
+	uint32_t bg;
+};
+
 static struct fbcon_config *config = NULL;
 
 #define RGB565_BLACK		0x0000
 #define RGB565_WHITE		0xffff
+#define RGB565_CYAN		0x07ff
+#define RGB565_BLUE		0x001f
+#define RGB565_SILVER		0xc618
+#define RGB565_YELLOW		0xffe0
+#define RGB565_ORANGE		0xfd20
+#define RGB565_RED		0xf800
 
 #define RGB888_BLACK            0x000000
 #define RGB888_WHITE            0xffffff
+#define RGB888_CYAN             0x00ffff
+#define RGB888_BLUE             0x0000FF
+#define RGB888_SILVER           0xc0c0c0
+#define RGB888_YELLOW           0xffff00
+#define RGB888_ORANGE           0xffa500
+#define RGB888_RED              0xff0000
 
 #define FONT_WIDTH		5
 #define FONT_HEIGHT		12
@@ -62,26 +79,50 @@
 
 static uint32_t			BGCOLOR;
 static uint32_t			FGCOLOR;
+static uint32_t			SELECT_BGCOLOR;
 
 static struct pos		cur_pos;
 static struct pos		max_pos;
+static struct fb_color		*fb_color_formats;
+static struct fb_color		fb_color_formats_555[] = {
+					[FBCON_COMMON_MSG] = {RGB565_WHITE, RGB565_BLACK},
+					[FBCON_UNLOCK_TITLE_MSG] = {RGB565_CYAN, RGB565_BLACK},
+					[FBCON_TITLE_MSG] = {RGB565_WHITE, RGB565_BLACK},
+					[FBCON_SUBTITLE_MSG] = {RGB565_SILVER, RGB565_BLACK},
+					[FBCON_YELLOW_MSG] = {RGB565_YELLOW, RGB565_BLACK},
+					[FBCON_ORANGE_MSG] = {RGB565_ORANGE, RGB565_BLACK},
+					[FBCON_RED_MSG] = {RGB565_RED, RGB565_BLACK},
+					[FBCON_LINE_COLOR] = {RGB565_WHITE, RGB565_WHITE},
+					[FBCON_SELECT_MSG_BG_COLOR] = {RGB565_WHITE, RGB565_BLUE}};
+
+static struct fb_color		fb_color_formats_888[] = {
+					[FBCON_COMMON_MSG] = {RGB888_WHITE, RGB888_BLACK},
+					[FBCON_UNLOCK_TITLE_MSG] = {RGB888_CYAN, RGB888_BLACK},
+					[FBCON_TITLE_MSG] = {RGB888_WHITE, RGB888_BLACK},
+					[FBCON_SUBTITLE_MSG] = {RGB888_SILVER, RGB888_BLACK},
+					[FBCON_YELLOW_MSG] = {RGB888_YELLOW, RGB888_BLACK},
+					[FBCON_ORANGE_MSG] = {RGB888_ORANGE, RGB888_BLACK},
+					[FBCON_RED_MSG] = {RGB888_RED, RGB888_BLACK},
+					[FBCON_LINE_COLOR] = {RGB888_WHITE, RGB888_WHITE},
+					[FBCON_SELECT_MSG_BG_COLOR] = {RGB888_WHITE, RGB888_BLUE}};
+
 
 static void fbcon_drawglyph(char *pixels, uint32_t paint, unsigned stride,
-			    unsigned bpp, unsigned *glyph)
+			    unsigned bpp, unsigned *glyph, unsigned scale_factor)
 {
 	unsigned x, y, i, j, k;
 	unsigned data, temp;
 	uint32_t fg_color = paint;
-	stride -= FONT_WIDTH * SCALE_FACTOR;
+	stride -= FONT_WIDTH * scale_factor;
 
 	data = glyph[0];
 	for (y = 0; y < FONT_HEIGHT / 2; ++y) {
 		temp = data;
-		for (i = 0; i < SCALE_FACTOR; i++) {
+		for (i = 0; i < scale_factor; i++) {
 			data = temp;
 			for (x = 0; x < FONT_WIDTH; ++x) {
 				if (data & 1) {
-					for (j = 0; j < SCALE_FACTOR; j++) {
+					for (j = 0; j < scale_factor; j++) {
 						fg_color = paint;
 						for (k = 0; k < bpp; k++) {
 							*pixels = (unsigned char) fg_color;
@@ -92,7 +133,7 @@
 				}
 				else
 				{
-					for (j = 0; j < SCALE_FACTOR; j++) {
+					for (j = 0; j < scale_factor; j++) {
 						pixels = pixels + bpp;
 					}
 				}
@@ -105,11 +146,11 @@
 	data = glyph[1];
 	for (y = 0; y < FONT_HEIGHT / 2; ++y) {
 		temp = data;
-		for (i = 0; i < SCALE_FACTOR; i++) {
+		for (i = 0; i < scale_factor; i++) {
 			data = temp;
 			for (x = 0; x < FONT_WIDTH; ++x) {
 				if (data & 1) {
-					for (j = 0; j < SCALE_FACTOR; j++) {
+					for (j = 0; j < scale_factor; j++) {
 						fg_color = paint;
 						for (k = 0; k < bpp; k++) {
 							*pixels = (unsigned char) fg_color;
@@ -120,7 +161,7 @@
 				}
 				else
 				{
-					for (j = 0; j < SCALE_FACTOR; j++) {
+					for (j = 0; j < scale_factor; j++) {
 						pixels = pixels + bpp;
 					}
 				}
@@ -132,6 +173,44 @@
 
 }
 
+void fbcon_draw_msg_background(unsigned y_start, unsigned y_end,
+	uint32_t old_paint, int update)
+{
+	unsigned i, j;
+	uint32_t bg_color, check_color, tmp_color, tmp1_color;
+	char *pixels;
+	unsigned count = config->width * (FONT_HEIGHT * (y_end - y_start) - 1);
+
+	pixels = config->base;
+	pixels += y_start * ((config->bpp / 8) * FONT_HEIGHT * config->width);
+
+	if (update) {
+		bg_color = SELECT_BGCOLOR;
+		check_color = old_paint;
+	} else {
+		bg_color = old_paint;
+		check_color = SELECT_BGCOLOR;
+	}
+
+	for (i = 0; i < count; i++) {
+		tmp1_color = bg_color;
+		tmp_color = 0;
+		for (j = 0; j < (config->bpp / 8); j++) {
+			tmp_color |= *(pixels+j) << j*8;
+		}
+
+		if (tmp_color == check_color) {
+			for (j = 0; j < (config->bpp / 8); j++) {
+				*pixels = (unsigned char) tmp1_color;
+				tmp1_color = tmp1_color >> 8;
+				pixels++;
+			}
+		} else {
+			pixels += config->bpp / 8;
+		}
+	}
+}
+
 static void fbcon_flush(void)
 {
 	unsigned total_x, total_y;
@@ -167,13 +246,50 @@
 	fbcon_flush();
 }
 
-/* TODO: take stride into account */
+void fbcon_draw_line()
+{
+	char *pixels;
+	uint32_t bg_color, tmp_color;
+	int i, j;
+
+	bg_color = fb_color_formats[FBCON_LINE_COLOR].bg;
+
+	pixels = config->base;
+	pixels += cur_pos.y * ((config->bpp / 8) * FONT_HEIGHT * config->width);
+	pixels += cur_pos.x * ((config->bpp / 8) * (FONT_WIDTH + 1));
+
+	for (i = 0; i < (int)config->width; i++) {
+		tmp_color = bg_color;
+		for (j = 0; j < (int)(config->bpp / 8); j++) {
+			*pixels = (unsigned char) tmp_color;
+			tmp_color = tmp_color >> 8;
+			pixels++;
+		}
+	}
+
+	cur_pos.y += 1;
+	cur_pos.x = 0;
+	if(cur_pos.y >= max_pos.y) {
+		cur_pos.y = max_pos.y - 1;
+		fbcon_scroll_up();
+	} else
+		fbcon_flush();
+}
+
+static void fbcon_set_colors(int type)
+{
+	BGCOLOR = fb_color_formats[type].bg;
+	FGCOLOR = fb_color_formats[type].fg;
+}
+
 void fbcon_clear(void)
 {
 	unsigned long i = 0, j = 0;
 	unsigned char *pixels = config->base;
 	unsigned count = config->width * config->height;
 	uint32_t bg_color;
+
+	fbcon_set_colors(FBCON_COMMON_MSG);
 	for (i = 0; i < count; i++) {
 		bg_color = BGCOLOR;
 		for (j = 0; j < (config->bpp / 8); j++) {
@@ -182,16 +298,11 @@
 			pixels++;
 		}
 	}
+	cur_pos.x = 0;
+	cur_pos.y = 0;
 }
 
-
-static void fbcon_set_colors(unsigned bg, unsigned fg)
-{
-	BGCOLOR = bg;
-	FGCOLOR = fg;
-}
-
-void fbcon_putc(char c)
+void fbcon_putc_factor(char c, int type, unsigned scale_factor)
 {
 	char *pixels;
 
@@ -213,18 +324,28 @@
 			return;
 	}
 
-	pixels = config->base;
-	pixels += cur_pos.y * SCALE_FACTOR * ((config->bpp / 8) * FONT_HEIGHT * config->width);
-	pixels += cur_pos.x * SCALE_FACTOR * ((config->bpp / 8) * (FONT_WIDTH + 1));
-	fbcon_drawglyph(pixels, FGCOLOR, config->stride, (config->bpp / 8),
-			font5x12 + (c - 32) * 2);
-
-	cur_pos.x++;
-	if (cur_pos.x < max_pos.x)
+	if (cur_pos.x == 0 && (unsigned char)c == ' ' &&
+		type != FBCON_SUBTITLE_MSG &&
+		type != FBCON_TITLE_MSG)
 		return;
 
+	fbcon_set_colors(type);
+
+	pixels = config->base;
+	pixels += cur_pos.y * ((config->bpp / 8) * FONT_HEIGHT * config->width);
+	pixels += cur_pos.x * scale_factor * ((config->bpp / 8) * (FONT_WIDTH + 1));
+
+	fbcon_drawglyph(pixels, FGCOLOR, config->stride, (config->bpp / 8),
+			font5x12 + (c - 32) * 2, scale_factor);
+
+	cur_pos.x++;
+	if (cur_pos.x >= (int)(max_pos.x / scale_factor))
+		goto newline;
+
+	return;
+
 newline:
-	cur_pos.y++;
+	cur_pos.y += scale_factor;
 	cur_pos.x = 0;
 	if(cur_pos.y >= max_pos.y) {
 		cur_pos.y = max_pos.y - 1;
@@ -233,39 +354,57 @@
 		fbcon_flush();
 }
 
+void fbcon_putc(char c)
+{
+	fbcon_putc_factor(c, FBCON_COMMON_MSG, SCALE_FACTOR);
+}
+
+uint32_t fbcon_get_current_line(void)
+{
+	return cur_pos.y;
+}
+
+uint32_t fbcon_get_max_x(void)
+{
+	return max_pos.x;
+}
+
+uint32_t fbcon_get_current_bg(void)
+{
+	return BGCOLOR;
+}
+
 void fbcon_setup(struct fbcon_config *_config)
 {
-	uint32_t bg = 0;
-	uint32_t fg = 0;
-
 	ASSERT(_config);
 
 	config = _config;
 
 	switch (config->format) {
 	case FB_FORMAT_RGB565:
-		fg = RGB565_WHITE;
-		bg = RGB565_BLACK;
+		fb_color_formats = fb_color_formats_555;
 		break;
-	case FB_FORMAT_RGB888:
-		fg = RGB888_WHITE;
-		bg = RGB888_BLACK;
-		break;
+        case FB_FORMAT_RGB888:
+		fb_color_formats = fb_color_formats_888;
+                break;
 	default:
 		dprintf(CRITICAL, "unknown framebuffer pixel format\n");
 		ASSERT(0);
 		break;
 	}
 
-	fbcon_set_colors(bg, fg);
+	SELECT_BGCOLOR = fb_color_formats[FBCON_SELECT_MSG_BG_COLOR].bg;
+	fbcon_set_colors(FBCON_COMMON_MSG);
 
 	cur_pos.x = 0;
 	cur_pos.y = 0;
-	max_pos.x = config->width / ((FONT_WIDTH + 1) * SCALE_FACTOR);
+	max_pos.x = config->width / (FONT_WIDTH+1);
 	max_pos.y = (config->height - 1) / FONT_HEIGHT;
+
 #if !DISPLAY_SPLASH_SCREEN
 	fbcon_clear();
 #endif
+
 }
 
 struct fbcon_config* fbcon_display(void)
diff --git a/include/dev/fbcon.h b/include/dev/fbcon.h
index e96b663..123532c 100644
--- a/include/dev/fbcon.h
+++ b/include/dev/fbcon.h
@@ -37,6 +37,25 @@
 #define LOGO_IMG_MAGIC_SIZE sizeof(LOGO_IMG_MAGIC) - 1
 #define LOGO_IMG_HEADER_SIZE 512
 
+enum fbcon_msg_type {
+	/* type for menu */
+	FBCON_COMMON_MSG = 0,
+	FBCON_UNLOCK_TITLE_MSG,
+	FBCON_TITLE_MSG,
+	FBCON_SUBTITLE_MSG,
+
+	/* type for warning */
+	FBCON_YELLOW_MSG,
+	FBCON_ORANGE_MSG,
+	FBCON_RED_MSG,
+
+	/* type for line color */
+	FBCON_LINE_COLOR,
+
+	/* and the select message's background */
+	FBCON_SELECT_MSG_BG_COLOR,
+};
+
 typedef struct logo_img_header {
 	unsigned char magic[LOGO_IMG_MAGIC_SIZE]; // "SPLASH!!"
 	uint32_t width;  // logo's width, little endian
@@ -74,5 +93,11 @@
 void fbcon_clear(void);
 struct fbcon_config* fbcon_display(void);
 void fbcon_extract_to_screen(logo_img_header *header, void* address);
-
+void fbcon_putc_factor(char c, int type, unsigned scale_factor);
+void fbcon_draw_msg_background(unsigned y_start, unsigned y_end,
+	uint32_t paint, int update);
+void fbcon_draw_line(void);
+uint32_t fbcon_get_current_line(void);
+uint32_t fbcon_get_current_bg(void);
+uint32_t fbcon_get_max_x(void);
 #endif /* __DEV_FBCON_H */