diff options
Diffstat (limited to 'usr/src/common/font/font.c')
| -rw-r--r-- | usr/src/common/font/font.c | 569 |
1 files changed, 569 insertions, 0 deletions
diff --git a/usr/src/common/font/font.c b/usr/src/common/font/font.c new file mode 100644 index 0000000000..f7a1abd914 --- /dev/null +++ b/usr/src/common/font/font.c @@ -0,0 +1,569 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Copyright 2017 Toomas Soome <tsoome@me.com> + */ + +/* + * Generic font related data and functions shared by early boot console + * in dboot, kernel startup and full kernel. + */ +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/tem_impl.h> +#include <sys/font.h> +#include <sys/sysmacros.h> + +/* + * To simplify my life, I am "temporarily" collecting the commonly used + * color bits here. The bits shared between loader, dboot, early boot, tem. + * This data would need some sort of API, but I am in no condition to figure + * something out right now. + */ + +/* ANSI color to sun color translation. */ +/* BEGIN CSTYLED */ +/* Bk Rd Gr Br Bl Mg Cy Wh */ +const uint8_t dim_xlate[] = { 1, 5, 3, 7, 2, 6, 4, 8 }; +const uint8_t brt_xlate[] = { 9, 13, 11, 15, 10, 14, 12, 0 }; + +/* The pc color here is actually referring to standard 16 color VGA map. */ +typedef enum pc_colors { + pc_black = 0, + pc_blue = 1, + pc_green = 2, + pc_cyan = 3, + pc_red = 4, + pc_magenta = 5, + pc_brown = 6, + pc_white = 7, + pc_grey = 8, + pc_brt_blue = 9, + pc_brt_green = 10, + pc_brt_cyan = 11, + pc_brt_red = 12, + pc_brt_magenta = 13, + pc_yellow = 14, + pc_brt_white = 15 +} pc_colors_t; + +const uint8_t solaris_color_to_pc_color[16] = { + pc_brt_white, /* 0 - brt_white */ + pc_black, /* 1 - black */ + pc_blue, /* 2 - blue */ + pc_green, /* 3 - green */ + pc_cyan, /* 4 - cyan */ + pc_red, /* 5 - red */ + pc_magenta, /* 6 - magenta */ + pc_brown, /* 7 - brown */ + pc_white, /* 8 - white */ + pc_grey, /* 9 - gery */ + pc_brt_blue, /* 10 - brt_blue */ + pc_brt_green, /* 11 - brt_green */ + pc_brt_cyan, /* 12 - brt_cyan */ + pc_brt_red, /* 13 - brt_red */ + pc_brt_magenta, /* 14 - brt_magenta */ + pc_yellow /* 15 - yellow */ +}; + +/* 4-bit to 24-bit color translation. */ +const text_cmap_t cmap4_to_24 = { +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 + Wh+ Bk Bl Gr Cy Rd Mg Br Wh Bk+ Bl+ Gr+ Cy+ Rd+ Mg+ Yw */ + .red = { + 0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff +}, + .green = { + 0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff +}, + .blue = { + 0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00 +} +}; +/* END CSTYLED */ + +/* + * Fonts are statically linked with this module. At some point an + * RFE might be desireable to allow dynamic font loading. The + * original intention to facilitate dynamic fonts can be seen + * by examining the data structures and set_font(). As much of + * the original code is retained but modified to be suited for + * traversing a list of static fonts. + */ + +/* + * Must be sorted by font size in descending order + */ +font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts); + +bitmap_data_t * +set_font(short *rows, short *cols, short h, short w) +{ + bitmap_data_t *font = NULL; + struct fontlist *fl; + unsigned height = h; + unsigned width = w; + + /* + * First check for manually loaded font. + */ + STAILQ_FOREACH(fl, &fonts, font_next) { + if (fl->font_flags == FONT_MANUAL || + fl->font_flags == FONT_BOOT) { + font = fl->font_data; + if (font->font == NULL && fl->font_load != NULL && + fl->font_name != NULL) { + font = fl->font_load(fl->font_name); + } + if (font == NULL || font->font == NULL) + font = NULL; + break; + } + } + + if (font != NULL) { + *rows = (height - BORDER_PIXELS) / font->height; + *cols = (width - BORDER_PIXELS) / font->width; + return (font); + } + + /* + * Find best font for these dimensions, or use default + * + * A 1 pixel border is the absolute minimum we could have + * as a border around the text window (BORDER_PIXELS = 2), + * however a slightly larger border not only looks better + * but for the fonts currently statically built into the + * emulator causes much better font selection for the + * normal range of screen resolutions. + */ + STAILQ_FOREACH(fl, &fonts, font_next) { + font = fl->font_data; + if ((((*rows * font->height) + BORDER_PIXELS) <= height) && + (((*cols * font->width) + BORDER_PIXELS) <= width)) { + if (font->font == NULL) { + if (fl->font_load != NULL && + fl->font_name != NULL) { + font = fl->font_load(fl->font_name); + } + if (font == NULL) + continue; + } + *rows = (height - BORDER_PIXELS) / font->height; + *cols = (width - BORDER_PIXELS) / font->width; + break; + } + font = NULL; + } + + if (font == NULL) { + /* + * We have fonts sorted smallest last, try it before + * falling back to builtin. + */ + fl = STAILQ_LAST(&fonts, fontlist, font_next); + if (fl != NULL && fl->font_load != NULL && + fl->font_name != NULL) { + font = fl->font_load(fl->font_name); + } + if (font == NULL) + font = &DEFAULT_FONT_DATA; + + *rows = (height - BORDER_PIXELS) / font->height; + *cols = (width - BORDER_PIXELS) / font->width; + } + + return (font); +} + +/* Binary search for the glyph. Return 0 if not found. */ +static uint16_t +font_bisearch(const struct font_map *map, uint32_t len, uint32_t src) +{ + unsigned min, mid, max; + + min = 0; + max = len - 1; + + /* Empty font map. */ + if (len == 0) + return (0); + /* Character below minimal entry. */ + if (src < map[0].font_src) + return (0); + /* Optimization: ASCII characters occur very often. */ + if (src <= map[0].font_src + map[0].font_len) + return (src - map[0].font_src + map[0].font_dst); + /* Character above maximum entry. */ + if (src > map[max].font_src + map[max].font_len) + return (0); + + /* Binary search. */ + while (max >= min) { + mid = (min + max) / 2; + if (src < map[mid].font_src) + max = mid - 1; + else if (src > map[mid].font_src + map[mid].font_len) + min = mid + 1; + else + return (src - map[mid].font_src + map[mid].font_dst); + } + + return (0); +} + +/* + * Return glyph bitmap. If glyph is not found, we will return bitmap + * for the first (offset 0) glyph. + */ +const uint8_t * +font_lookup(const struct font *vf, uint32_t c) +{ + uint32_t src; + uint16_t dst; + size_t stride; + + src = TEM_CHAR(c); + + /* Substitute bold with normal if not found. */ + if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) { + dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD], + vf->vf_map_count[VFNT_MAP_BOLD], src); + if (dst != 0) + goto found; + } + dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL], + vf->vf_map_count[VFNT_MAP_NORMAL], src); + +found: + stride = howmany(vf->vf_width, 8) * vf->vf_height; + return (&vf->vf_bytes[dst * stride]); +} + +/* + * bit_to_pix4 is for 4-bit frame buffers. It will write one output byte + * for each 2 bits of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. + * + * Assuming foreground is 0001 and background is 0000... + * An input data byte of 0x53 will output the bit pattern + * 00000001 00000001 00000000 00010001. + */ + +void +font_bit_to_pix4( + struct font *f, + uint8_t *dest, + uint32_t c, + uint8_t fg_color, + uint8_t bg_color) +{ + uint32_t row; + int byte; + int i; + const uint8_t *cp, *ul; + uint8_t data; + uint8_t nibblett; + int bytes_wide; + + if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) + ul = font_lookup(f, 0x0332); /* combining low line */ + else + ul = NULL; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + for (byte = 0; byte < bytes_wide; byte++) { + if (ul == NULL) + data = *cp++; + else + data = *cp++ | *ul++; + for (i = 0; i < 4; i++) { + nibblett = (data >> ((3-i) * 2)) & 0x3; + switch (nibblett) { + case 0x0: + *dest++ = bg_color << 4 | bg_color; + break; + case 0x1: + *dest++ = bg_color << 4 | fg_color; + break; + case 0x2: + *dest++ = fg_color << 4 | bg_color; + break; + case 0x3: + *dest++ = fg_color << 4 | fg_color; + break; + } + } + } + } +} + +/* + * bit_to_pix8 is for 8-bit frame buffers. It will write one output byte + * for each bit of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. + * + * Assuming foreground is 00000001 and background is 00000000... + * An input data byte of 0x53 will output the bit pattern + * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001. + */ + +void +font_bit_to_pix8( + struct font *f, + uint8_t *dest, + uint32_t c, + uint8_t fg_color, + uint8_t bg_color) +{ + uint32_t row; + int byte; + int i; + const uint8_t *cp, *ul; + uint8_t data; + int bytes_wide; + uint8_t mask; + int bitsleft, nbits; + + if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) + ul = font_lookup(f, 0x0332); /* combining low line */ + else + ul = NULL; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + bitsleft = f->vf_width; + for (byte = 0; byte < bytes_wide; byte++) { + if (ul == NULL) + data = *cp++; + else + data = *cp++ | *ul++; + mask = 0x80; + nbits = MIN(8, bitsleft); + bitsleft -= nbits; + for (i = 0; i < nbits; i++) { + *dest++ = (data & mask ? fg_color: bg_color); + mask = mask >> 1; + } + } + } +} + +/* + * bit_to_pix16 is for 16-bit frame buffers. It will write two output bytes + * for each bit of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. + * + * Assuming foreground is 11111111 11111111 + * and background is 00000000 00000000 + * An input data byte of 0x53 will output the bit pattern + * + * 00000000 00000000 + * 11111111 11111111 + * 00000000 00000000 + * 11111111 11111111 + * 00000000 00000000 + * 00000000 00000000 + * 11111111 11111111 + * 11111111 11111111 + * + */ + +void +font_bit_to_pix16( + struct font *f, + uint16_t *dest, + uint32_t c, + uint16_t fg_color16, + uint16_t bg_color16) +{ + uint32_t row; + int byte; + int i; + const uint8_t *cp, *ul; + uint16_t data, d; + int bytes_wide; + int bitsleft, nbits; + + if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) + ul = font_lookup(f, 0x0332); /* combining low line */ + else + ul = NULL; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + bitsleft = f->vf_width; + for (byte = 0; byte < bytes_wide; byte++) { + if (ul == NULL) + data = *cp++; + else + data = *cp++ | *ul++; + nbits = MIN(8, bitsleft); + bitsleft -= nbits; + for (i = 0; i < nbits; i++) { + d = ((data << i) & 0x80 ? + fg_color16 : bg_color16); + *dest++ = d; + } + } + } +} + +/* + * bit_to_pix24 is for 24-bit frame buffers. It will write three output bytes + * for each bit of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. + * + * Assuming foreground is 11111111 11111111 11111111 + * and background is 00000000 00000000 00000000 + * An input data byte of 0x53 will output the bit pattern + * + * 00000000 00000000 00000000 + * 11111111 11111111 11111111 + * 00000000 00000000 00000000 + * 11111111 11111111 11111111 + * 00000000 00000000 00000000 + * 00000000 00000000 00000000 + * 11111111 11111111 11111111 + * 11111111 11111111 11111111 + * + */ + +void +font_bit_to_pix24( + struct font *f, + uint8_t *dest, + uint32_t c, + uint32_t fg_color32, + uint32_t bg_color32) +{ + uint32_t row; + int byte; + int i; + const uint8_t *cp, *ul; + uint32_t data, d; + int bytes_wide; + int bitsleft, nbits; + + if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) + ul = font_lookup(f, 0x0332); /* combining low line */ + else + ul = NULL; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + bitsleft = f->vf_width; + for (byte = 0; byte < bytes_wide; byte++) { + if (ul == NULL) + data = *cp++; + else + data = *cp++ | *ul++; + + nbits = MIN(8, bitsleft); + bitsleft -= nbits; + for (i = 0; i < nbits; i++) { + d = ((data << i) & 0x80 ? + fg_color32 : bg_color32); + *dest++ = d & 0xff; + *dest++ = (d >> 8) & 0xff; + *dest++ = (d >> 16) & 0xff; + } + } + } +} + +/* + * bit_to_pix32 is for 32-bit frame buffers. It will write four output bytes + * for each bit of input bitmap. It inverts the input bits before + * doing the output translation, for reverse video. Note that each + * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the + * high-order byte set to zero. + * + * Assuming foreground is 00000000 11111111 11111111 11111111 + * and background is 00000000 00000000 00000000 00000000 + * An input data byte of 0x53 will output the bit pattern + * + * 00000000 00000000 00000000 00000000 + * 00000000 11111111 11111111 11111111 + * 00000000 00000000 00000000 00000000 + * 00000000 11111111 11111111 11111111 + * 00000000 00000000 00000000 00000000 + * 00000000 00000000 00000000 00000000 + * 00000000 11111111 11111111 11111111 + * 00000000 11111111 11111111 11111111 + * + */ + +void +font_bit_to_pix32( + struct font *f, + uint32_t *dest, + uint32_t c, + uint32_t fg_color32, + uint32_t bg_color32) +{ + uint32_t row; + int byte; + int i; + const uint8_t *cp, *ul; + uint32_t data; + int bytes_wide; + int bitsleft, nbits; + + if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE) + ul = font_lookup(f, 0x0332); /* combining low line */ + else + ul = NULL; + + cp = font_lookup(f, c); + bytes_wide = (f->vf_width + 7) / 8; + + for (row = 0; row < f->vf_height; row++) { + bitsleft = f->vf_width; + for (byte = 0; byte < bytes_wide; byte++) { + if (ul == NULL) + data = *cp++; + else + data = *cp++ | *ul++; + nbits = MIN(8, bitsleft); + bitsleft -= nbits; + for (i = 0; i < nbits; i++) { + *dest++ = ((data << i) & 0x80 ? + fg_color32 : bg_color32); + } + } + } +} |
