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