xref: /illumos-gate/usr/src/common/font/font.c (revision 3aa6c13072f3d4792a18693e916aed260a496c1f)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright 2017 Toomas Soome <tsoome@me.com>
29  */
30 
31 /*
32  * Generic font related data and functions shared by early boot console
33  * in dboot, kernel startup and full kernel.
34  */
35 #include <sys/types.h>
36 #include <sys/systm.h>
37 #include <sys/tem_impl.h>
38 #include <sys/rgb.h>
39 #include <sys/font.h>
40 #include <sys/sysmacros.h>
41 
42 /*
43  * To simplify my life, I am "temporarily" collecting the commonly used
44  * color bits here. The bits shared between loader, dboot, early boot, tem.
45  * This data would need some sort of API, but I am in no condition to figure
46  * something out right now.
47  */
48 
49 /* ANSI color to sun color translation. */
50 /* BEGIN CSTYLED */
51 /*                                         Bk  Rd  Gr  Br  Bl  Mg  Cy  Wh */
52 const uint8_t dim_xlate[XLATE_NCOLORS] = {  1,  5,  3,  7,  2,  6,  4,  8 };
53 const uint8_t brt_xlate[XLATE_NCOLORS] = {  9, 13, 11, 15, 10, 14, 12,  0 };
54 
55 const uint8_t solaris_color_to_pc_color[16] = {
56 	pc_brt_white,		/*  0 - brt_white	*/
57 	pc_black,		/*  1 - black		*/
58 	pc_blue,		/*  2 - blue		*/
59 	pc_green,		/*  3 - green		*/
60 	pc_cyan,		/*  4 - cyan		*/
61 	pc_red,			/*  5 - red		*/
62 	pc_magenta,		/*  6 - magenta		*/
63 	pc_brown,		/*  7 - brown		*/
64 	pc_white,		/*  8 - white		*/
65 	pc_grey,		/*  9 - grey		*/
66 	pc_brt_blue,		/* 10 - brt_blue	*/
67 	pc_brt_green,		/* 11 - brt_green	*/
68 	pc_brt_cyan,		/* 12 - brt_cyan	*/
69 	pc_brt_red,		/* 13 - brt_red		*/
70 	pc_brt_magenta,		/* 14 - brt_magenta	*/
71 	pc_yellow		/* 15 - yellow		*/
72 };
73 
74 const uint8_t pc_color_to_solaris_color[16] = {
75 	sun_black,		/*  0 - black		*/
76 	sun_blue,		/*  1 - blue		*/
77 	sun_green,		/*  2 - green		*/
78 	sun_cyan,		/*  3 - cyan		*/
79 	sun_red,		/*  4 - red		*/
80 	sun_magenta,		/*  5 - magenta		*/
81 	sun_brown,		/*  6 - brown		*/
82 	sun_white,		/*  7 - white		*/
83 	sun_grey,		/*  8 - grey		*/
84 	sun_brt_blue,		/*  9 - brt_blue	*/
85 	sun_brt_green,		/* 10 - brt_green	*/
86 	sun_brt_cyan,		/* 11 - brt_cyan	*/
87 	sun_brt_red,		/* 12 - brt_red		*/
88 	sun_brt_magenta,	/* 13 - brt_magenta	*/
89 	sun_yellow,		/* 14 - yellow		*/
90 	sun_brt_white		/* 15 - brt_white	*/
91 };
92 
93 /* 4-bit to 24-bit color translation. */
94 const text_cmap_t cmap4_to_24 = {
95 /* 0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
96   Wh+  Bk   Bl   Gr   Cy   Rd   Mg   Br   Wh   Bk+  Bl+  Gr+  Cy+  Rd+  Mg+  Yw */
97   .red = {
98  0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff
99 },
100   .green = {
101  0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff
102 },
103   .blue = {
104  0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
105 }
106 };
107 /* END CSTYLED */
108 
109 static uint32_t
110 rgb_to_color(const rgb_t *rgb, uint32_t r, uint32_t g, uint32_t b)
111 {
112 	uint32_t color;
113 	int pos, size;
114 
115 	pos = rgb->red.pos;
116 	size = rgb->red.size;
117 	color = ((r * ((1 << size) - 1)) / 0xff) << pos;
118 
119 	pos = rgb->green.pos;
120 	size = rgb->green.size;
121 	color |= (((g * ((1 << size) - 1)) / 0xff) << pos);
122 
123 	pos = rgb->blue.pos;
124 	size = rgb->blue.size;
125 	color |= (((b * ((1 << size) - 1)) / 0xff) << pos);
126 
127 	return (color);
128 }
129 
130 uint32_t
131 rgb_color_map(const rgb_t *rgb, uint8_t index)
132 {
133 	uint32_t color, code, gray, level;
134 
135 	if (index < 16) {
136 		color = rgb_to_color(rgb, cmap4_to_24.red[index],
137 		    cmap4_to_24.green[index], cmap4_to_24.blue[index]);
138 		return (color);
139 	}
140 
141 	/* 6x6x6 color cube */
142 	if (index > 15 && index < 232) {
143 		uint32_t red, green, blue;
144 
145 		for (red = 0; red < 6; red++) {
146 			for (green = 0; green < 6; green++) {
147 				for (blue = 0; blue < 6; blue++) {
148 					code = 16 + (red * 36) +
149 					    (green * 6) + blue;
150 					if (code != index)
151 						continue;
152 					red = red ? (red * 40 + 55) : 0;
153 					green = green ? (green * 40 + 55) : 0;
154 					blue = blue ? (blue * 40 + 55) : 0;
155 					color = rgb_to_color(rgb, red, green,
156 					    blue);
157 					return (color);
158 				}
159 			}
160 		}
161 	}
162 
163 	/* colors 232-255 are a grayscale ramp */
164 	for (gray = 0; gray < 24; gray++) {
165 		level = (gray * 10) + 8;
166 		code = 232 + gray;
167 		if (code == index)
168 			break;
169 	}
170 	return (rgb_to_color(rgb, level, level, level));
171 }
172 /*
173  * Fonts are statically linked with this module. At some point an
174  * RFE might be desireable to allow dynamic font loading.  The
175  * original intention to facilitate dynamic fonts can be seen
176  * by examining the data structures and set_font().  As much of
177  * the original code is retained but modified to be suited for
178  * traversing a list of static fonts.
179  */
180 
181 /*
182  * Must be sorted by font size in descending order
183  */
184 font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
185 
186 /*
187  * Reset font flags to FONT_AUTO.
188  */
189 void
190 reset_font_flags(void)
191 {
192 	struct fontlist *fl;
193 
194 	STAILQ_FOREACH(fl, &fonts, font_next) {
195 		fl->font_flags = FONT_AUTO;
196 	}
197 }
198 
199 bitmap_data_t *
200 set_font(short *rows, short *cols, short h, short w)
201 {
202 	bitmap_data_t *font = NULL;
203 	struct fontlist	*fl;
204 	unsigned height = h;
205 	unsigned width = w;
206 
207 	/*
208 	 * First check for manually loaded font.
209 	 */
210 	STAILQ_FOREACH(fl, &fonts, font_next) {
211 		if (fl->font_flags == FONT_MANUAL ||
212 		    fl->font_flags == FONT_BOOT) {
213 			font = fl->font_data;
214 			if (font->font == NULL && fl->font_load != NULL &&
215 			    fl->font_name != NULL) {
216 				font = fl->font_load(fl->font_name);
217 			}
218 			if (font == NULL || font->font == NULL)
219 				font = NULL;
220 			break;
221 		}
222 	}
223 
224 	if (font != NULL) {
225 		*rows = (height - BORDER_PIXELS) / font->height;
226 		*cols = (width - BORDER_PIXELS) / font->width;
227 		return (font);
228 	}
229 
230 	/*
231 	 * Find best font for these dimensions, or use default
232 	 *
233 	 * A 1 pixel border is the absolute minimum we could have
234 	 * as a border around the text window (BORDER_PIXELS = 2),
235 	 * however a slightly larger border not only looks better
236 	 * but for the fonts currently statically built into the
237 	 * emulator causes much better font selection for the
238 	 * normal range of screen resolutions.
239 	 */
240 	STAILQ_FOREACH(fl, &fonts, font_next) {
241 		font = fl->font_data;
242 		if ((((*rows * font->height) + BORDER_PIXELS) <= height) &&
243 		    (((*cols * font->width) + BORDER_PIXELS) <= width)) {
244 			if (font->font == NULL ||
245 			    fl->font_flags == FONT_RELOAD) {
246 				if (fl->font_load != NULL &&
247 				    fl->font_name != NULL) {
248 					font = fl->font_load(fl->font_name);
249 				}
250 				if (font == NULL)
251 					continue;
252 			}
253 			*rows = (height - BORDER_PIXELS) / font->height;
254 			*cols = (width - BORDER_PIXELS) / font->width;
255 			break;
256 		}
257 		font = NULL;
258 	}
259 
260 	if (font == NULL) {
261 		/*
262 		 * We have fonts sorted smallest last, try it before
263 		 * falling back to builtin.
264 		 */
265 		fl = STAILQ_LAST(&fonts, fontlist, font_next);
266 		if (fl != NULL && fl->font_load != NULL &&
267 		    fl->font_name != NULL) {
268 			font = fl->font_load(fl->font_name);
269 		}
270 		if (font == NULL)
271 			font = &DEFAULT_FONT_DATA;
272 
273 		*rows = (height - BORDER_PIXELS) / font->height;
274 		*cols = (width - BORDER_PIXELS) / font->width;
275 	}
276 
277 	return (font);
278 }
279 
280 /* Binary search for the glyph. Return 0 if not found. */
281 static uint16_t
282 font_bisearch(const struct font_map *map, uint32_t len, uint32_t src)
283 {
284 	unsigned min, mid, max;
285 
286 	min = 0;
287 	max = len - 1;
288 
289 	/* Empty font map. */
290 	if (len == 0)
291 		return (0);
292 	/* Character below minimal entry. */
293 	if (src < map[0].font_src)
294 		return (0);
295 	/* Optimization: ASCII characters occur very often. */
296 	if (src <= map[0].font_src + map[0].font_len)
297 		return (src - map[0].font_src + map[0].font_dst);
298 	/* Character above maximum entry. */
299 	if (src > map[max].font_src + map[max].font_len)
300 		return (0);
301 
302 	/* Binary search. */
303 	while (max >= min) {
304 		mid = (min + max) / 2;
305 		if (src < map[mid].font_src)
306 			max = mid - 1;
307 		else if (src > map[mid].font_src + map[mid].font_len)
308 			min = mid + 1;
309 		else
310 			return (src - map[mid].font_src + map[mid].font_dst);
311 	}
312 
313 	return (0);
314 }
315 
316 /*
317  * Return glyph bitmap. If glyph is not found, we will return bitmap
318  * for the first (offset 0) glyph.
319  */
320 const uint8_t *
321 font_lookup(const struct font *vf, uint32_t c)
322 {
323 	uint32_t src;
324 	uint16_t dst;
325 	size_t stride;
326 
327 	src = TEM_CHAR(c);
328 
329 	/* Substitute bold with normal if not found. */
330 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) {
331 		dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD],
332 		    vf->vf_map_count[VFNT_MAP_BOLD], src);
333 		if (dst != 0)
334 			goto found;
335 	}
336 	dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL],
337 	    vf->vf_map_count[VFNT_MAP_NORMAL], src);
338 
339 found:
340 	stride = howmany(vf->vf_width, 8) * vf->vf_height;
341 	return (&vf->vf_bytes[dst * stride]);
342 }
343 
344 /*
345  * bit_to_pix4 is for 4-bit frame buffers.  It will write one output byte
346  * for each 2 bits of input bitmap.  It inverts the input bits before
347  * doing the output translation, for reverse video.
348  *
349  * Assuming foreground is 0001 and background is 0000...
350  * An input data byte of 0x53 will output the bit pattern
351  * 00000001 00000001 00000000 00010001.
352  */
353 
354 void
355 font_bit_to_pix4(
356     struct font *f,
357     uint8_t *dest,
358     uint32_t c,
359     uint8_t fg_color,
360     uint8_t bg_color)
361 {
362 	uint32_t row;
363 	int	byte;
364 	int	i;
365 	const uint8_t *cp, *ul;
366 	uint8_t	data;
367 	uint8_t	nibblett;
368 	int	bytes_wide;
369 
370 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
371 		ul = font_lookup(f, 0x0332);	/* combining low line */
372 	else
373 		ul = NULL;
374 
375 	cp = font_lookup(f, c);
376 	bytes_wide = (f->vf_width + 7) / 8;
377 
378 	for (row = 0; row < f->vf_height; row++) {
379 		for (byte = 0; byte < bytes_wide; byte++) {
380 			if (ul == NULL)
381 				data = *cp++;
382 			else
383 				data = *cp++ | *ul++;
384 			for (i = 0; i < 4; i++) {
385 				nibblett = (data >> ((3-i) * 2)) & 0x3;
386 				switch (nibblett) {
387 				case 0x0:
388 					*dest++ = bg_color << 4 | bg_color;
389 					break;
390 				case 0x1:
391 					*dest++ = bg_color << 4 | fg_color;
392 					break;
393 				case 0x2:
394 					*dest++ = fg_color << 4 | bg_color;
395 					break;
396 				case 0x3:
397 					*dest++ = fg_color << 4 | fg_color;
398 					break;
399 				}
400 			}
401 		}
402 	}
403 }
404 
405 /*
406  * bit_to_pix8 is for 8-bit frame buffers.  It will write one output byte
407  * for each bit of input bitmap.  It inverts the input bits before
408  * doing the output translation, for reverse video.
409  *
410  * Assuming foreground is 00000001 and background is 00000000...
411  * An input data byte of 0x53 will output the bit pattern
412  * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
413  */
414 
415 void
416 font_bit_to_pix8(
417     struct font *f,
418     uint8_t *dest,
419     uint32_t c,
420     uint8_t fg_color,
421     uint8_t bg_color)
422 {
423 	uint32_t row;
424 	int	byte;
425 	int	i;
426 	const uint8_t *cp, *ul;
427 	uint8_t	data;
428 	int	bytes_wide;
429 	uint8_t	mask;
430 	int	bitsleft, nbits;
431 
432 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
433 		ul = font_lookup(f, 0x0332);	/* combining low line */
434 	else
435 		ul = NULL;
436 
437 	cp = font_lookup(f, c);
438 	bytes_wide = (f->vf_width + 7) / 8;
439 
440 	for (row = 0; row < f->vf_height; row++) {
441 		bitsleft = f->vf_width;
442 		for (byte = 0; byte < bytes_wide; byte++) {
443 			if (ul == NULL)
444 				data = *cp++;
445 			else
446 				data = *cp++ | *ul++;
447 			mask = 0x80;
448 			nbits = MIN(8, bitsleft);
449 			bitsleft -= nbits;
450 			for (i = 0; i < nbits; i++) {
451 				*dest++ = (data & mask ? fg_color: bg_color);
452 				mask = mask >> 1;
453 			}
454 		}
455 	}
456 }
457 
458 /*
459  * bit_to_pix16 is for 16-bit frame buffers.  It will write two output bytes
460  * for each bit of input bitmap.  It inverts the input bits before
461  * doing the output translation, for reverse video.
462  *
463  * Assuming foreground is 11111111 11111111
464  * and background is 00000000 00000000
465  * An input data byte of 0x53 will output the bit pattern
466  *
467  * 00000000 00000000
468  * 11111111 11111111
469  * 00000000 00000000
470  * 11111111 11111111
471  * 00000000 00000000
472  * 00000000 00000000
473  * 11111111 11111111
474  * 11111111 11111111
475  *
476  */
477 
478 void
479 font_bit_to_pix16(
480     struct font *f,
481     uint16_t *dest,
482     uint32_t c,
483     uint16_t fg_color16,
484     uint16_t bg_color16)
485 {
486 	uint32_t row;
487 	int	byte;
488 	int	i;
489 	const uint8_t *cp, *ul;
490 	uint16_t data, d;
491 	int	bytes_wide;
492 	int	bitsleft, nbits;
493 
494 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
495 		ul = font_lookup(f, 0x0332);	/* combining low line */
496 	else
497 		ul = NULL;
498 
499 	cp = font_lookup(f, c);
500 	bytes_wide = (f->vf_width + 7) / 8;
501 
502 	for (row = 0; row < f->vf_height; row++) {
503 		bitsleft = f->vf_width;
504 		for (byte = 0; byte < bytes_wide; byte++) {
505 			if (ul == NULL)
506 				data = *cp++;
507 			else
508 				data = *cp++ | *ul++;
509 			nbits = MIN(8, bitsleft);
510 			bitsleft -= nbits;
511 			for (i = 0; i < nbits; i++) {
512 				d = ((data << i) & 0x80 ?
513 				    fg_color16 : bg_color16);
514 				*dest++ = d;
515 			}
516 		}
517 	}
518 }
519 
520 /*
521  * bit_to_pix24 is for 24-bit frame buffers.  It will write three output bytes
522  * for each bit of input bitmap.  It inverts the input bits before
523  * doing the output translation, for reverse video.
524  *
525  * Assuming foreground is 11111111 11111111 11111111
526  * and background is 00000000 00000000 00000000
527  * An input data byte of 0x53 will output the bit pattern
528  *
529  * 00000000 00000000 00000000
530  * 11111111 11111111 11111111
531  * 00000000 00000000 00000000
532  * 11111111 11111111 11111111
533  * 00000000 00000000 00000000
534  * 00000000 00000000 00000000
535  * 11111111 11111111 11111111
536  * 11111111 11111111 11111111
537  *
538  */
539 
540 void
541 font_bit_to_pix24(
542     struct font *f,
543     uint8_t *dest,
544     uint32_t c,
545     uint32_t fg_color32,
546     uint32_t bg_color32)
547 {
548 	uint32_t row;
549 	int	byte;
550 	int	i;
551 	const uint8_t *cp, *ul;
552 	uint32_t data, d;
553 	int	bytes_wide;
554 	int	bitsleft, nbits;
555 
556 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
557 		ul = font_lookup(f, 0x0332);	/* combining low line */
558 	else
559 		ul = NULL;
560 
561 	cp = font_lookup(f, c);
562 	bytes_wide = (f->vf_width + 7) / 8;
563 
564 	for (row = 0; row < f->vf_height; row++) {
565 		bitsleft = f->vf_width;
566 		for (byte = 0; byte < bytes_wide; byte++) {
567 			if (ul == NULL)
568 				data = *cp++;
569 			else
570 				data = *cp++ | *ul++;
571 
572 			nbits = MIN(8, bitsleft);
573 			bitsleft -= nbits;
574 			for (i = 0; i < nbits; i++) {
575 				d = ((data << i) & 0x80 ?
576 				    fg_color32 : bg_color32);
577 				*dest++ = d & 0xff;
578 				*dest++ = (d >> 8) & 0xff;
579 				*dest++ = (d >> 16) & 0xff;
580 			}
581 		}
582 	}
583 }
584 
585 /*
586  * bit_to_pix32 is for 32-bit frame buffers.  It will write four output bytes
587  * for each bit of input bitmap.  It inverts the input bits before
588  * doing the output translation, for reverse video.  Note that each
589  * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
590  * high-order byte set to zero.
591  *
592  * Assuming foreground is 00000000 11111111 11111111 11111111
593  * and background is 00000000 00000000 00000000 00000000
594  * An input data byte of 0x53 will output the bit pattern
595  *
596  * 00000000 00000000 00000000 00000000
597  * 00000000 11111111 11111111 11111111
598  * 00000000 00000000 00000000 00000000
599  * 00000000 11111111 11111111 11111111
600  * 00000000 00000000 00000000 00000000
601  * 00000000 00000000 00000000 00000000
602  * 00000000 11111111 11111111 11111111
603  * 00000000 11111111 11111111 11111111
604  *
605  */
606 
607 void
608 font_bit_to_pix32(
609     struct font *f,
610     uint32_t *dest,
611     uint32_t c,
612     uint32_t fg_color32,
613     uint32_t bg_color32)
614 {
615 	uint32_t row;
616 	int	byte;
617 	int	i;
618 	const uint8_t *cp, *ul;
619 	uint32_t data;
620 	int	bytes_wide;
621 	int	bitsleft, nbits;
622 
623 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
624 		ul = font_lookup(f, 0x0332);	/* combining low line */
625 	else
626 		ul = NULL;
627 
628 	cp = font_lookup(f, c);
629 	bytes_wide = (f->vf_width + 7) / 8;
630 
631 	for (row = 0; row < f->vf_height; row++) {
632 		bitsleft = f->vf_width;
633 		for (byte = 0; byte < bytes_wide; byte++) {
634 			if (ul == NULL)
635 				data = *cp++;
636 			else
637 				data = *cp++ | *ul++;
638 			nbits = MIN(8, bitsleft);
639 			bitsleft -= nbits;
640 			for (i = 0; i < nbits; i++) {
641 				*dest++ = ((data << i) & 0x80 ?
642 				    fg_color32 : bg_color32);
643 			}
644 		}
645 	}
646 }
647