xref: /illumos-gate/usr/src/common/font/font.c (revision a92282e44f968185a6bba094d1e5fece2da819cf)
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 - gery		*/
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 /* 4-bit to 24-bit color translation. */
75 const text_cmap_t cmap4_to_24 = {
76 /* 0    1    2    3    4    5    6    7    8    9   10   11   12   13   14   15
77   Wh+  Bk   Bl   Gr   Cy   Rd   Mg   Br   Wh   Bk+  Bl+  Gr+  Cy+  Rd+  Mg+  Yw */
78   .red = {
79  0xff,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x40,0x00,0x00,0x00,0xff,0xff,0xff
80 },
81   .green = {
82  0xff,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x80,0x40,0x00,0xff,0xff,0x00,0x00,0xff
83 },
84   .blue = {
85  0xff,0x00,0x80,0x00,0x80,0x00,0x80,0x00,0x80,0x40,0xff,0x00,0xff,0x00,0xff,0x00
86 }
87 };
88 /* END CSTYLED */
89 
90 static uint32_t
91 rgb_to_color(const rgb_t *rgb, uint32_t r, uint32_t g, uint32_t b)
92 {
93 	uint32_t color;
94 	int pos, size;
95 
96 	pos = rgb->red.pos;
97 	size = rgb->red.size;
98 	color = ((r * ((1 << size) - 1)) / 0xff) << pos;
99 
100 	pos = rgb->green.pos;
101 	size = rgb->green.size;
102 	color |= (((g * ((1 << size) - 1)) / 0xff) << pos);
103 
104 	pos = rgb->blue.pos;
105 	size = rgb->blue.size;
106 	color |= (((b * ((1 << size) - 1)) / 0xff) << pos);
107 
108 	return (color);
109 }
110 
111 uint32_t
112 rgb_color_map(const rgb_t *rgb, uint8_t index)
113 {
114 	uint32_t color, code, gray, level;
115 
116 	if (index < 16) {
117 		color = rgb_to_color(rgb, cmap4_to_24.red[index],
118 		    cmap4_to_24.green[index], cmap4_to_24.blue[index]);
119 		return (color);
120 	}
121 
122 	/* 6x6x6 color cube */
123 	if (index > 15 && index < 232) {
124 		uint32_t red, green, blue;
125 
126 		for (red = 0; red < 6; red++) {
127 			for (green = 0; green < 6; green++) {
128 				for (blue = 0; blue < 6; blue++) {
129 					code = 16 + (red * 36) +
130 					    (green * 6) + blue;
131 					if (code != index)
132 						continue;
133 					red = red ? (red * 40 + 55) : 0;
134 					green = green ? (green * 40 + 55) : 0;
135 					blue = blue ? (blue * 40 + 55) : 0;
136 					color = rgb_to_color(rgb, red, green,
137 					    blue);
138 					return (color);
139 				}
140 			}
141 		}
142 	}
143 
144 	/* colors 232-255 are a grayscale ramp */
145 	for (gray = 0; gray < 24; gray++) {
146 		level = (gray * 10) + 8;
147 		code = 232 + gray;
148 		if (code == index)
149 			break;
150 	}
151 	return (rgb_to_color(rgb, level, level, level));
152 }
153 /*
154  * Fonts are statically linked with this module. At some point an
155  * RFE might be desireable to allow dynamic font loading.  The
156  * original intention to facilitate dynamic fonts can be seen
157  * by examining the data structures and set_font().  As much of
158  * the original code is retained but modified to be suited for
159  * traversing a list of static fonts.
160  */
161 
162 /*
163  * Must be sorted by font size in descending order
164  */
165 font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
166 
167 /*
168  * Reset font flags to FONT_AUTO.
169  */
170 void
171 reset_font_flags(void)
172 {
173 	struct fontlist *fl;
174 
175 	STAILQ_FOREACH(fl, &fonts, font_next) {
176 		fl->font_flags = FONT_AUTO;
177 	}
178 }
179 
180 bitmap_data_t *
181 set_font(short *rows, short *cols, short h, short w)
182 {
183 	bitmap_data_t *font = NULL;
184 	struct fontlist	*fl;
185 	unsigned height = h;
186 	unsigned width = w;
187 
188 	/*
189 	 * First check for manually loaded font.
190 	 */
191 	STAILQ_FOREACH(fl, &fonts, font_next) {
192 		if (fl->font_flags == FONT_MANUAL ||
193 		    fl->font_flags == FONT_BOOT) {
194 			font = fl->font_data;
195 			if (font->font == NULL && fl->font_load != NULL &&
196 			    fl->font_name != NULL) {
197 				font = fl->font_load(fl->font_name);
198 			}
199 			if (font == NULL || font->font == NULL)
200 				font = NULL;
201 			break;
202 		}
203 	}
204 
205 	if (font != NULL) {
206 		*rows = (height - BORDER_PIXELS) / font->height;
207 		*cols = (width - BORDER_PIXELS) / font->width;
208 		return (font);
209 	}
210 
211 	/*
212 	 * Find best font for these dimensions, or use default
213 	 *
214 	 * A 1 pixel border is the absolute minimum we could have
215 	 * as a border around the text window (BORDER_PIXELS = 2),
216 	 * however a slightly larger border not only looks better
217 	 * but for the fonts currently statically built into the
218 	 * emulator causes much better font selection for the
219 	 * normal range of screen resolutions.
220 	 */
221 	STAILQ_FOREACH(fl, &fonts, font_next) {
222 		font = fl->font_data;
223 		if ((((*rows * font->height) + BORDER_PIXELS) <= height) &&
224 		    (((*cols * font->width) + BORDER_PIXELS) <= width)) {
225 			if (font->font == NULL ||
226 			    fl->font_flags == FONT_RELOAD) {
227 				if (fl->font_load != NULL &&
228 				    fl->font_name != NULL) {
229 					font = fl->font_load(fl->font_name);
230 				}
231 				if (font == NULL)
232 					continue;
233 			}
234 			*rows = (height - BORDER_PIXELS) / font->height;
235 			*cols = (width - BORDER_PIXELS) / font->width;
236 			break;
237 		}
238 		font = NULL;
239 	}
240 
241 	if (font == NULL) {
242 		/*
243 		 * We have fonts sorted smallest last, try it before
244 		 * falling back to builtin.
245 		 */
246 		fl = STAILQ_LAST(&fonts, fontlist, font_next);
247 		if (fl != NULL && fl->font_load != NULL &&
248 		    fl->font_name != NULL) {
249 			font = fl->font_load(fl->font_name);
250 		}
251 		if (font == NULL)
252 			font = &DEFAULT_FONT_DATA;
253 
254 		*rows = (height - BORDER_PIXELS) / font->height;
255 		*cols = (width - BORDER_PIXELS) / font->width;
256 	}
257 
258 	return (font);
259 }
260 
261 /* Binary search for the glyph. Return 0 if not found. */
262 static uint16_t
263 font_bisearch(const struct font_map *map, uint32_t len, uint32_t src)
264 {
265 	unsigned min, mid, max;
266 
267 	min = 0;
268 	max = len - 1;
269 
270 	/* Empty font map. */
271 	if (len == 0)
272 		return (0);
273 	/* Character below minimal entry. */
274 	if (src < map[0].font_src)
275 		return (0);
276 	/* Optimization: ASCII characters occur very often. */
277 	if (src <= map[0].font_src + map[0].font_len)
278 		return (src - map[0].font_src + map[0].font_dst);
279 	/* Character above maximum entry. */
280 	if (src > map[max].font_src + map[max].font_len)
281 		return (0);
282 
283 	/* Binary search. */
284 	while (max >= min) {
285 		mid = (min + max) / 2;
286 		if (src < map[mid].font_src)
287 			max = mid - 1;
288 		else if (src > map[mid].font_src + map[mid].font_len)
289 			min = mid + 1;
290 		else
291 			return (src - map[mid].font_src + map[mid].font_dst);
292 	}
293 
294 	return (0);
295 }
296 
297 /*
298  * Return glyph bitmap. If glyph is not found, we will return bitmap
299  * for the first (offset 0) glyph.
300  */
301 const uint8_t *
302 font_lookup(const struct font *vf, uint32_t c)
303 {
304 	uint32_t src;
305 	uint16_t dst;
306 	size_t stride;
307 
308 	src = TEM_CHAR(c);
309 
310 	/* Substitute bold with normal if not found. */
311 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) {
312 		dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD],
313 		    vf->vf_map_count[VFNT_MAP_BOLD], src);
314 		if (dst != 0)
315 			goto found;
316 	}
317 	dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL],
318 	    vf->vf_map_count[VFNT_MAP_NORMAL], src);
319 
320 found:
321 	stride = howmany(vf->vf_width, 8) * vf->vf_height;
322 	return (&vf->vf_bytes[dst * stride]);
323 }
324 
325 /*
326  * bit_to_pix4 is for 4-bit frame buffers.  It will write one output byte
327  * for each 2 bits of input bitmap.  It inverts the input bits before
328  * doing the output translation, for reverse video.
329  *
330  * Assuming foreground is 0001 and background is 0000...
331  * An input data byte of 0x53 will output the bit pattern
332  * 00000001 00000001 00000000 00010001.
333  */
334 
335 void
336 font_bit_to_pix4(
337     struct font *f,
338     uint8_t *dest,
339     uint32_t c,
340     uint8_t fg_color,
341     uint8_t bg_color)
342 {
343 	uint32_t row;
344 	int	byte;
345 	int	i;
346 	const uint8_t *cp, *ul;
347 	uint8_t	data;
348 	uint8_t	nibblett;
349 	int	bytes_wide;
350 
351 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
352 		ul = font_lookup(f, 0x0332);	/* combining low line */
353 	else
354 		ul = NULL;
355 
356 	cp = font_lookup(f, c);
357 	bytes_wide = (f->vf_width + 7) / 8;
358 
359 	for (row = 0; row < f->vf_height; row++) {
360 		for (byte = 0; byte < bytes_wide; byte++) {
361 			if (ul == NULL)
362 				data = *cp++;
363 			else
364 				data = *cp++ | *ul++;
365 			for (i = 0; i < 4; i++) {
366 				nibblett = (data >> ((3-i) * 2)) & 0x3;
367 				switch (nibblett) {
368 				case 0x0:
369 					*dest++ = bg_color << 4 | bg_color;
370 					break;
371 				case 0x1:
372 					*dest++ = bg_color << 4 | fg_color;
373 					break;
374 				case 0x2:
375 					*dest++ = fg_color << 4 | bg_color;
376 					break;
377 				case 0x3:
378 					*dest++ = fg_color << 4 | fg_color;
379 					break;
380 				}
381 			}
382 		}
383 	}
384 }
385 
386 /*
387  * bit_to_pix8 is for 8-bit frame buffers.  It will write one output byte
388  * for each bit of input bitmap.  It inverts the input bits before
389  * doing the output translation, for reverse video.
390  *
391  * Assuming foreground is 00000001 and background is 00000000...
392  * An input data byte of 0x53 will output the bit pattern
393  * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
394  */
395 
396 void
397 font_bit_to_pix8(
398     struct font *f,
399     uint8_t *dest,
400     uint32_t c,
401     uint8_t fg_color,
402     uint8_t bg_color)
403 {
404 	uint32_t row;
405 	int	byte;
406 	int	i;
407 	const uint8_t *cp, *ul;
408 	uint8_t	data;
409 	int	bytes_wide;
410 	uint8_t	mask;
411 	int	bitsleft, nbits;
412 
413 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
414 		ul = font_lookup(f, 0x0332);	/* combining low line */
415 	else
416 		ul = NULL;
417 
418 	cp = font_lookup(f, c);
419 	bytes_wide = (f->vf_width + 7) / 8;
420 
421 	for (row = 0; row < f->vf_height; row++) {
422 		bitsleft = f->vf_width;
423 		for (byte = 0; byte < bytes_wide; byte++) {
424 			if (ul == NULL)
425 				data = *cp++;
426 			else
427 				data = *cp++ | *ul++;
428 			mask = 0x80;
429 			nbits = MIN(8, bitsleft);
430 			bitsleft -= nbits;
431 			for (i = 0; i < nbits; i++) {
432 				*dest++ = (data & mask ? fg_color: bg_color);
433 				mask = mask >> 1;
434 			}
435 		}
436 	}
437 }
438 
439 /*
440  * bit_to_pix16 is for 16-bit frame buffers.  It will write two output bytes
441  * for each bit of input bitmap.  It inverts the input bits before
442  * doing the output translation, for reverse video.
443  *
444  * Assuming foreground is 11111111 11111111
445  * and background is 00000000 00000000
446  * An input data byte of 0x53 will output the bit pattern
447  *
448  * 00000000 00000000
449  * 11111111 11111111
450  * 00000000 00000000
451  * 11111111 11111111
452  * 00000000 00000000
453  * 00000000 00000000
454  * 11111111 11111111
455  * 11111111 11111111
456  *
457  */
458 
459 void
460 font_bit_to_pix16(
461     struct font *f,
462     uint16_t *dest,
463     uint32_t c,
464     uint16_t fg_color16,
465     uint16_t bg_color16)
466 {
467 	uint32_t row;
468 	int	byte;
469 	int	i;
470 	const uint8_t *cp, *ul;
471 	uint16_t data, d;
472 	int	bytes_wide;
473 	int	bitsleft, nbits;
474 
475 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
476 		ul = font_lookup(f, 0x0332);	/* combining low line */
477 	else
478 		ul = NULL;
479 
480 	cp = font_lookup(f, c);
481 	bytes_wide = (f->vf_width + 7) / 8;
482 
483 	for (row = 0; row < f->vf_height; row++) {
484 		bitsleft = f->vf_width;
485 		for (byte = 0; byte < bytes_wide; byte++) {
486 			if (ul == NULL)
487 				data = *cp++;
488 			else
489 				data = *cp++ | *ul++;
490 			nbits = MIN(8, bitsleft);
491 			bitsleft -= nbits;
492 			for (i = 0; i < nbits; i++) {
493 				d = ((data << i) & 0x80 ?
494 				    fg_color16 : bg_color16);
495 				*dest++ = d;
496 			}
497 		}
498 	}
499 }
500 
501 /*
502  * bit_to_pix24 is for 24-bit frame buffers.  It will write three output bytes
503  * for each bit of input bitmap.  It inverts the input bits before
504  * doing the output translation, for reverse video.
505  *
506  * Assuming foreground is 11111111 11111111 11111111
507  * and background is 00000000 00000000 00000000
508  * An input data byte of 0x53 will output the bit pattern
509  *
510  * 00000000 00000000 00000000
511  * 11111111 11111111 11111111
512  * 00000000 00000000 00000000
513  * 11111111 11111111 11111111
514  * 00000000 00000000 00000000
515  * 00000000 00000000 00000000
516  * 11111111 11111111 11111111
517  * 11111111 11111111 11111111
518  *
519  */
520 
521 void
522 font_bit_to_pix24(
523     struct font *f,
524     uint8_t *dest,
525     uint32_t c,
526     uint32_t fg_color32,
527     uint32_t bg_color32)
528 {
529 	uint32_t row;
530 	int	byte;
531 	int	i;
532 	const uint8_t *cp, *ul;
533 	uint32_t data, d;
534 	int	bytes_wide;
535 	int	bitsleft, nbits;
536 
537 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
538 		ul = font_lookup(f, 0x0332);	/* combining low line */
539 	else
540 		ul = NULL;
541 
542 	cp = font_lookup(f, c);
543 	bytes_wide = (f->vf_width + 7) / 8;
544 
545 	for (row = 0; row < f->vf_height; row++) {
546 		bitsleft = f->vf_width;
547 		for (byte = 0; byte < bytes_wide; byte++) {
548 			if (ul == NULL)
549 				data = *cp++;
550 			else
551 				data = *cp++ | *ul++;
552 
553 			nbits = MIN(8, bitsleft);
554 			bitsleft -= nbits;
555 			for (i = 0; i < nbits; i++) {
556 				d = ((data << i) & 0x80 ?
557 				    fg_color32 : bg_color32);
558 				*dest++ = d & 0xff;
559 				*dest++ = (d >> 8) & 0xff;
560 				*dest++ = (d >> 16) & 0xff;
561 			}
562 		}
563 	}
564 }
565 
566 /*
567  * bit_to_pix32 is for 32-bit frame buffers.  It will write four output bytes
568  * for each bit of input bitmap.  It inverts the input bits before
569  * doing the output translation, for reverse video.  Note that each
570  * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
571  * high-order byte set to zero.
572  *
573  * Assuming foreground is 00000000 11111111 11111111 11111111
574  * and background is 00000000 00000000 00000000 00000000
575  * An input data byte of 0x53 will output the bit pattern
576  *
577  * 00000000 00000000 00000000 00000000
578  * 00000000 11111111 11111111 11111111
579  * 00000000 00000000 00000000 00000000
580  * 00000000 11111111 11111111 11111111
581  * 00000000 00000000 00000000 00000000
582  * 00000000 00000000 00000000 00000000
583  * 00000000 11111111 11111111 11111111
584  * 00000000 11111111 11111111 11111111
585  *
586  */
587 
588 void
589 font_bit_to_pix32(
590     struct font *f,
591     uint32_t *dest,
592     uint32_t c,
593     uint32_t fg_color32,
594     uint32_t bg_color32)
595 {
596 	uint32_t row;
597 	int	byte;
598 	int	i;
599 	const uint8_t *cp, *ul;
600 	uint32_t data;
601 	int	bytes_wide;
602 	int	bitsleft, nbits;
603 
604 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
605 		ul = font_lookup(f, 0x0332);	/* combining low line */
606 	else
607 		ul = NULL;
608 
609 	cp = font_lookup(f, c);
610 	bytes_wide = (f->vf_width + 7) / 8;
611 
612 	for (row = 0; row < f->vf_height; row++) {
613 		bitsleft = f->vf_width;
614 		for (byte = 0; byte < bytes_wide; byte++) {
615 			if (ul == NULL)
616 				data = *cp++;
617 			else
618 				data = *cp++ | *ul++;
619 			nbits = MIN(8, bitsleft);
620 			bitsleft -= nbits;
621 			for (i = 0; i < nbits; i++) {
622 				*dest++ = ((data << i) & 0x80 ?
623 				    fg_color32 : bg_color32);
624 			}
625 		}
626 	}
627 }
628