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