xref: /illumos-gate/usr/src/common/font/font.c (revision 89af4c7b)
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 __weak_symbol bitmap_data_t *
200 gfx_get_font(void)
201 {
202 	return (NULL);
203 }
204 
205 bitmap_data_t *
206 set_font(short *rows, short *cols, short h, short w)
207 {
208 	bitmap_data_t *font = NULL;
209 	struct fontlist	*fl;
210 	unsigned height = h;
211 	unsigned width = w;
212 
213 	/*
214 	 * First check for manually loaded font.
215 	 */
216 	STAILQ_FOREACH(fl, &fonts, font_next) {
217 		if (fl->font_flags == FONT_MANUAL ||
218 		    fl->font_flags == FONT_BOOT) {
219 			font = fl->font_data;
220 			if (font->font == NULL && fl->font_load != NULL &&
221 			    fl->font_name != NULL) {
222 				font = fl->font_load(fl->font_name);
223 			}
224 			if (font == NULL || font->font == NULL)
225 				font = NULL;
226 			break;
227 		}
228 	}
229 
230 	if (font == NULL)
231 		font = gfx_get_font();
232 
233 	if (font != NULL) {
234 		*rows = (height - BORDER_PIXELS) / font->height;
235 		*cols = (width - BORDER_PIXELS) / font->width;
236 		return (font);
237 	}
238 
239 	/*
240 	 * Find best font for these dimensions, or use default
241 	 *
242 	 * A 1 pixel border is the absolute minimum we could have
243 	 * as a border around the text window (BORDER_PIXELS = 2),
244 	 * however a slightly larger border not only looks better
245 	 * but for the fonts currently statically built into the
246 	 * emulator causes much better font selection for the
247 	 * normal range of screen resolutions.
248 	 */
249 	STAILQ_FOREACH(fl, &fonts, font_next) {
250 		font = fl->font_data;
251 		if ((((*rows * font->height) + BORDER_PIXELS) <= height) &&
252 		    (((*cols * font->width) + BORDER_PIXELS) <= width)) {
253 			if (font->font == NULL ||
254 			    fl->font_flags == FONT_RELOAD) {
255 				if (fl->font_load != NULL &&
256 				    fl->font_name != NULL) {
257 					font = fl->font_load(fl->font_name);
258 				}
259 				if (font == NULL)
260 					continue;
261 			}
262 			*rows = (height - BORDER_PIXELS) / font->height;
263 			*cols = (width - BORDER_PIXELS) / font->width;
264 			break;
265 		}
266 		font = NULL;
267 	}
268 
269 	if (font == NULL) {
270 		/*
271 		 * We have fonts sorted smallest last, try it before
272 		 * falling back to builtin.
273 		 */
274 		fl = STAILQ_LAST(&fonts, fontlist, font_next);
275 		if (fl != NULL && fl->font_load != NULL &&
276 		    fl->font_name != NULL) {
277 			font = fl->font_load(fl->font_name);
278 		}
279 		if (font == NULL)
280 			font = &DEFAULT_FONT_DATA;
281 
282 		*rows = (height - BORDER_PIXELS) / font->height;
283 		*cols = (width - BORDER_PIXELS) / font->width;
284 	}
285 
286 	return (font);
287 }
288 
289 /* Binary search for the glyph. Return 0 if not found. */
290 static uint16_t
291 font_bisearch(const struct font_map *map, uint32_t len, uint32_t src)
292 {
293 	unsigned min, mid, max;
294 
295 	min = 0;
296 	max = len - 1;
297 
298 	/* Empty font map. */
299 	if (len == 0)
300 		return (0);
301 	/* Character below minimal entry. */
302 	if (src < map[0].font_src)
303 		return (0);
304 	/* Optimization: ASCII characters occur very often. */
305 	if (src <= map[0].font_src + map[0].font_len)
306 		return (src - map[0].font_src + map[0].font_dst);
307 	/* Character above maximum entry. */
308 	if (src > map[max].font_src + map[max].font_len)
309 		return (0);
310 
311 	/* Binary search. */
312 	while (max >= min) {
313 		mid = (min + max) / 2;
314 		if (src < map[mid].font_src)
315 			max = mid - 1;
316 		else if (src > map[mid].font_src + map[mid].font_len)
317 			min = mid + 1;
318 		else
319 			return (src - map[mid].font_src + map[mid].font_dst);
320 	}
321 
322 	return (0);
323 }
324 
325 /*
326  * Return glyph bitmap. If glyph is not found, we will return bitmap
327  * for the first (offset 0) glyph.
328  */
329 const uint8_t *
330 font_lookup(const struct font *vf, uint32_t c)
331 {
332 	uint32_t src;
333 	uint16_t dst;
334 	size_t stride;
335 
336 	src = TEM_CHAR(c);
337 
338 	/* Substitute bold with normal if not found. */
339 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) {
340 		dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD],
341 		    vf->vf_map_count[VFNT_MAP_BOLD], src);
342 		if (dst != 0)
343 			goto found;
344 	}
345 	dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL],
346 	    vf->vf_map_count[VFNT_MAP_NORMAL], src);
347 
348 found:
349 	stride = howmany(vf->vf_width, 8) * vf->vf_height;
350 	return (&vf->vf_bytes[dst * stride]);
351 }
352 
353 /*
354  * bit_to_pix4 is for 4-bit frame buffers.  It will write one output byte
355  * for each 2 bits of input bitmap.  It inverts the input bits before
356  * doing the output translation, for reverse video.
357  *
358  * Assuming foreground is 0001 and background is 0000...
359  * An input data byte of 0x53 will output the bit pattern
360  * 00000001 00000001 00000000 00010001.
361  */
362 
363 void
364 font_bit_to_pix4(
365     struct font *f,
366     uint8_t *dest,
367     uint32_t c,
368     uint8_t fg_color,
369     uint8_t bg_color)
370 {
371 	uint32_t row;
372 	int	byte;
373 	int	i;
374 	const uint8_t *cp, *ul;
375 	uint8_t	data;
376 	uint8_t	nibblett;
377 	int	bytes_wide;
378 
379 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
380 		ul = font_lookup(f, 0x0332);	/* combining low line */
381 	else
382 		ul = NULL;
383 
384 	cp = font_lookup(f, c);
385 	bytes_wide = (f->vf_width + 7) / 8;
386 
387 	for (row = 0; row < f->vf_height; row++) {
388 		for (byte = 0; byte < bytes_wide; byte++) {
389 			if (ul == NULL)
390 				data = *cp++;
391 			else
392 				data = *cp++ | *ul++;
393 			for (i = 0; i < 4; i++) {
394 				nibblett = (data >> ((3-i) * 2)) & 0x3;
395 				switch (nibblett) {
396 				case 0x0:
397 					*dest++ = bg_color << 4 | bg_color;
398 					break;
399 				case 0x1:
400 					*dest++ = bg_color << 4 | fg_color;
401 					break;
402 				case 0x2:
403 					*dest++ = fg_color << 4 | bg_color;
404 					break;
405 				case 0x3:
406 					*dest++ = fg_color << 4 | fg_color;
407 					break;
408 				}
409 			}
410 		}
411 	}
412 }
413 
414 /*
415  * bit_to_pix8 is for 8-bit frame buffers.  It will write one output byte
416  * for each bit of input bitmap.  It inverts the input bits before
417  * doing the output translation, for reverse video.
418  *
419  * Assuming foreground is 00000001 and background is 00000000...
420  * An input data byte of 0x53 will output the bit pattern
421  * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
422  */
423 
424 void
425 font_bit_to_pix8(
426     struct font *f,
427     uint8_t *dest,
428     uint32_t c,
429     uint8_t fg_color,
430     uint8_t bg_color)
431 {
432 	uint32_t row;
433 	int	byte;
434 	int	i;
435 	const uint8_t *cp, *ul;
436 	uint8_t	data;
437 	int	bytes_wide;
438 	uint8_t	mask;
439 	int	bitsleft, nbits;
440 
441 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
442 		ul = font_lookup(f, 0x0332);	/* combining low line */
443 	else
444 		ul = NULL;
445 
446 	cp = font_lookup(f, c);
447 	bytes_wide = (f->vf_width + 7) / 8;
448 
449 	for (row = 0; row < f->vf_height; row++) {
450 		bitsleft = f->vf_width;
451 		for (byte = 0; byte < bytes_wide; byte++) {
452 			if (ul == NULL)
453 				data = *cp++;
454 			else
455 				data = *cp++ | *ul++;
456 			mask = 0x80;
457 			nbits = MIN(8, bitsleft);
458 			bitsleft -= nbits;
459 			for (i = 0; i < nbits; i++) {
460 				*dest++ = (data & mask ? fg_color: bg_color);
461 				mask = mask >> 1;
462 			}
463 		}
464 	}
465 }
466 
467 /*
468  * bit_to_pix16 is for 16-bit frame buffers.  It will write two output bytes
469  * for each bit of input bitmap.  It inverts the input bits before
470  * doing the output translation, for reverse video.
471  *
472  * Assuming foreground is 11111111 11111111
473  * and background is 00000000 00000000
474  * An input data byte of 0x53 will output the bit pattern
475  *
476  * 00000000 00000000
477  * 11111111 11111111
478  * 00000000 00000000
479  * 11111111 11111111
480  * 00000000 00000000
481  * 00000000 00000000
482  * 11111111 11111111
483  * 11111111 11111111
484  *
485  */
486 
487 void
488 font_bit_to_pix16(
489     struct font *f,
490     uint16_t *dest,
491     uint32_t c,
492     uint16_t fg_color16,
493     uint16_t bg_color16)
494 {
495 	uint32_t row;
496 	int	byte;
497 	int	i;
498 	const uint8_t *cp, *ul;
499 	uint16_t data, d;
500 	int	bytes_wide;
501 	int	bitsleft, nbits;
502 
503 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
504 		ul = font_lookup(f, 0x0332);	/* combining low line */
505 	else
506 		ul = NULL;
507 
508 	cp = font_lookup(f, c);
509 	bytes_wide = (f->vf_width + 7) / 8;
510 
511 	for (row = 0; row < f->vf_height; row++) {
512 		bitsleft = f->vf_width;
513 		for (byte = 0; byte < bytes_wide; byte++) {
514 			if (ul == NULL)
515 				data = *cp++;
516 			else
517 				data = *cp++ | *ul++;
518 			nbits = MIN(8, bitsleft);
519 			bitsleft -= nbits;
520 			for (i = 0; i < nbits; i++) {
521 				d = ((data << i) & 0x80 ?
522 				    fg_color16 : bg_color16);
523 				*dest++ = d;
524 			}
525 		}
526 	}
527 }
528 
529 /*
530  * bit_to_pix24 is for 24-bit frame buffers.  It will write three output bytes
531  * for each bit of input bitmap.  It inverts the input bits before
532  * doing the output translation, for reverse video.
533  *
534  * Assuming foreground is 11111111 11111111 11111111
535  * and background is 00000000 00000000 00000000
536  * An input data byte of 0x53 will output the bit pattern
537  *
538  * 00000000 00000000 00000000
539  * 11111111 11111111 11111111
540  * 00000000 00000000 00000000
541  * 11111111 11111111 11111111
542  * 00000000 00000000 00000000
543  * 00000000 00000000 00000000
544  * 11111111 11111111 11111111
545  * 11111111 11111111 11111111
546  *
547  */
548 
549 void
550 font_bit_to_pix24(
551     struct font *f,
552     uint8_t *dest,
553     uint32_t c,
554     uint32_t fg_color32,
555     uint32_t bg_color32)
556 {
557 	uint32_t row;
558 	int	byte;
559 	int	i;
560 	const uint8_t *cp, *ul;
561 	uint32_t data, d;
562 	int	bytes_wide;
563 	int	bitsleft, nbits;
564 
565 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
566 		ul = font_lookup(f, 0x0332);	/* combining low line */
567 	else
568 		ul = NULL;
569 
570 	cp = font_lookup(f, c);
571 	bytes_wide = (f->vf_width + 7) / 8;
572 
573 	for (row = 0; row < f->vf_height; row++) {
574 		bitsleft = f->vf_width;
575 		for (byte = 0; byte < bytes_wide; byte++) {
576 			if (ul == NULL)
577 				data = *cp++;
578 			else
579 				data = *cp++ | *ul++;
580 
581 			nbits = MIN(8, bitsleft);
582 			bitsleft -= nbits;
583 			for (i = 0; i < nbits; i++) {
584 				d = ((data << i) & 0x80 ?
585 				    fg_color32 : bg_color32);
586 				*dest++ = d & 0xff;
587 				*dest++ = (d >> 8) & 0xff;
588 				*dest++ = (d >> 16) & 0xff;
589 			}
590 		}
591 	}
592 }
593 
594 /*
595  * bit_to_pix32 is for 32-bit frame buffers.  It will write four output bytes
596  * for each bit of input bitmap.  It inverts the input bits before
597  * doing the output translation, for reverse video.  Note that each
598  * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
599  * high-order byte set to zero.
600  *
601  * Assuming foreground is 00000000 11111111 11111111 11111111
602  * and background is 00000000 00000000 00000000 00000000
603  * An input data byte of 0x53 will output the bit pattern
604  *
605  * 00000000 00000000 00000000 00000000
606  * 00000000 11111111 11111111 11111111
607  * 00000000 00000000 00000000 00000000
608  * 00000000 11111111 11111111 11111111
609  * 00000000 00000000 00000000 00000000
610  * 00000000 00000000 00000000 00000000
611  * 00000000 11111111 11111111 11111111
612  * 00000000 11111111 11111111 11111111
613  *
614  */
615 
616 void
617 font_bit_to_pix32(
618     struct font *f,
619     uint32_t *dest,
620     uint32_t c,
621     uint32_t fg_color32,
622     uint32_t bg_color32)
623 {
624 	uint32_t row;
625 	int	byte;
626 	int	i;
627 	const uint8_t *cp, *ul;
628 	uint32_t data;
629 	int	bytes_wide;
630 	int	bitsleft, nbits;
631 
632 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
633 		ul = font_lookup(f, 0x0332);	/* combining low line */
634 	else
635 		ul = NULL;
636 
637 	cp = font_lookup(f, c);
638 	bytes_wide = (f->vf_width + 7) / 8;
639 
640 	for (row = 0; row < f->vf_height; row++) {
641 		bitsleft = f->vf_width;
642 		for (byte = 0; byte < bytes_wide; byte++) {
643 			if (ul == NULL)
644 				data = *cp++;
645 			else
646 				data = *cp++ | *ul++;
647 			nbits = MIN(8, bitsleft);
648 			bitsleft -= nbits;
649 			for (i = 0; i < nbits; i++) {
650 				*dest++ = ((data << i) & 0x80 ?
651 				    fg_color32 : bg_color32);
652 			}
653 		}
654 	}
655 }
656