xref: /illumos-gate/usr/src/common/font/font.c (revision 2bc92914)
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/font.h>
39 #include <sys/sysmacros.h>
40 
41 /*
42  * To simplify my life, I am "temporarily" collecting the commonly used
43  * color bits here. The bits shared between loader, dboot, early boot, tem.
44  * This data would need some sort of API, but I am in no condition to figure
45  * something out right now.
46  */
47 
48 /* ANSI color to sun color translation. */
49 /* BEGIN CSTYLED */
50 /*                            Bk  Rd  Gr  Br  Bl  Mg  Cy  Wh */
51 const uint8_t dim_xlate[] = {  1,  5,  3,  7,  2,  6,  4,  8 };
52 const uint8_t brt_xlate[] = {  9, 13, 11, 15, 10, 14, 12,  0 };
53 
54 /* The pc color here is actually referring to standard 16 color VGA map. */
55 typedef enum pc_colors {
56 	pc_black	= 0,
57 	pc_blue		= 1,
58 	pc_green	= 2,
59 	pc_cyan		= 3,
60 	pc_red		= 4,
61 	pc_magenta	= 5,
62 	pc_brown	= 6,
63 	pc_white	= 7,
64 	pc_grey		= 8,
65 	pc_brt_blue	= 9,
66 	pc_brt_green	= 10,
67 	pc_brt_cyan	= 11,
68 	pc_brt_red	= 12,
69 	pc_brt_magenta	= 13,
70 	pc_yellow	= 14,
71 	pc_brt_white	= 15
72 } pc_colors_t;
73 
74 const uint8_t solaris_color_to_pc_color[16] = {
75 	pc_brt_white,		/*  0 - brt_white	*/
76 	pc_black,		/*  1 - black		*/
77 	pc_blue,		/*  2 - blue		*/
78 	pc_green,		/*  3 - green		*/
79 	pc_cyan,		/*  4 - cyan		*/
80 	pc_red,			/*  5 - red		*/
81 	pc_magenta,		/*  6 - magenta		*/
82 	pc_brown,		/*  7 - brown		*/
83 	pc_white,		/*  8 - white		*/
84 	pc_grey,		/*  9 - gery		*/
85 	pc_brt_blue,		/* 10 - brt_blue	*/
86 	pc_brt_green,		/* 11 - brt_green	*/
87 	pc_brt_cyan,		/* 12 - brt_cyan	*/
88 	pc_brt_red,		/* 13 - brt_red		*/
89 	pc_brt_magenta,		/* 14 - brt_magenta	*/
90 	pc_yellow		/* 15 - yellow		*/
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 /*
110  * Fonts are statically linked with this module. At some point an
111  * RFE might be desireable to allow dynamic font loading.  The
112  * original intention to facilitate dynamic fonts can be seen
113  * by examining the data structures and set_font().  As much of
114  * the original code is retained but modified to be suited for
115  * traversing a list of static fonts.
116  */
117 
118 /*
119  * Must be sorted by font size in descending order
120  */
121 font_list_t fonts = STAILQ_HEAD_INITIALIZER(fonts);
122 
123 bitmap_data_t *
124 set_font(short *rows, short *cols, short h, short w)
125 {
126 	bitmap_data_t *font = NULL;
127 	struct fontlist	*fl;
128 	unsigned height = h;
129 	unsigned width = w;
130 
131 	/*
132 	 * First check for manually loaded font.
133 	 */
134 	STAILQ_FOREACH(fl, &fonts, font_next) {
135 		if (fl->font_flags == FONT_MANUAL ||
136 		    fl->font_flags == FONT_BOOT) {
137 			font = fl->font_data;
138 			if (font->font == NULL && fl->font_load != NULL &&
139 			    fl->font_name != NULL) {
140 				font = fl->font_load(fl->font_name);
141 			}
142 			if (font == NULL || font->font == NULL)
143 				font = NULL;
144 			break;
145 		}
146 	}
147 
148 	if (font != NULL) {
149 		*rows = (height - BORDER_PIXELS) / font->height;
150 		*cols = (width - BORDER_PIXELS) / font->width;
151 		return (font);
152 	}
153 
154 	/*
155 	 * Find best font for these dimensions, or use default
156 	 *
157 	 * A 1 pixel border is the absolute minimum we could have
158 	 * as a border around the text window (BORDER_PIXELS = 2),
159 	 * however a slightly larger border not only looks better
160 	 * but for the fonts currently statically built into the
161 	 * emulator causes much better font selection for the
162 	 * normal range of screen resolutions.
163 	 */
164 	STAILQ_FOREACH(fl, &fonts, font_next) {
165 		font = fl->font_data;
166 		if ((((*rows * font->height) + BORDER_PIXELS) <= height) &&
167 		    (((*cols * font->width) + BORDER_PIXELS) <= width)) {
168 			if (font->font == NULL) {
169 				if (fl->font_load != NULL &&
170 				    fl->font_name != NULL) {
171 					font = fl->font_load(fl->font_name);
172 				}
173 				if (font == NULL)
174 					continue;
175 			}
176 			*rows = (height - BORDER_PIXELS) / font->height;
177 			*cols = (width - BORDER_PIXELS) / font->width;
178 			break;
179 		}
180 		font = NULL;
181 	}
182 
183 	if (font == NULL) {
184 		/*
185 		 * We have fonts sorted smallest last, try it before
186 		 * falling back to builtin.
187 		 */
188 		fl = STAILQ_LAST(&fonts, fontlist, font_next);
189 		if (fl != NULL && fl->font_load != NULL &&
190 		    fl->font_name != NULL) {
191 			font = fl->font_load(fl->font_name);
192 		}
193 		if (font == NULL)
194 			font = &DEFAULT_FONT_DATA;
195 
196 		*rows = (height - BORDER_PIXELS) / font->height;
197 		*cols = (width - BORDER_PIXELS) / font->width;
198 	}
199 
200 	return (font);
201 }
202 
203 /* Binary search for the glyph. Return 0 if not found. */
204 static uint16_t
205 font_bisearch(const struct font_map *map, uint32_t len, uint32_t src)
206 {
207 	unsigned min, mid, max;
208 
209 	min = 0;
210 	max = len - 1;
211 
212 	/* Empty font map. */
213 	if (len == 0)
214 		return (0);
215 	/* Character below minimal entry. */
216 	if (src < map[0].font_src)
217 		return (0);
218 	/* Optimization: ASCII characters occur very often. */
219 	if (src <= map[0].font_src + map[0].font_len)
220 		return (src - map[0].font_src + map[0].font_dst);
221 	/* Character above maximum entry. */
222 	if (src > map[max].font_src + map[max].font_len)
223 		return (0);
224 
225 	/* Binary search. */
226 	while (max >= min) {
227 		mid = (min + max) / 2;
228 		if (src < map[mid].font_src)
229 			max = mid - 1;
230 		else if (src > map[mid].font_src + map[mid].font_len)
231 			min = mid + 1;
232 		else
233 			return (src - map[mid].font_src + map[mid].font_dst);
234 	}
235 
236 	return (0);
237 }
238 
239 /*
240  * Return glyph bitmap. If glyph is not found, we will return bitmap
241  * for the first (offset 0) glyph.
242  */
243 const uint8_t *
244 font_lookup(const struct font *vf, uint32_t c)
245 {
246 	uint32_t src;
247 	uint16_t dst;
248 	size_t stride;
249 
250 	src = TEM_CHAR(c);
251 
252 	/* Substitute bold with normal if not found. */
253 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_BOLD) {
254 		dst = font_bisearch(vf->vf_map[VFNT_MAP_BOLD],
255 		    vf->vf_map_count[VFNT_MAP_BOLD], src);
256 		if (dst != 0)
257 			goto found;
258 	}
259 	dst = font_bisearch(vf->vf_map[VFNT_MAP_NORMAL],
260 	    vf->vf_map_count[VFNT_MAP_NORMAL], src);
261 
262 found:
263 	stride = howmany(vf->vf_width, 8) * vf->vf_height;
264 	return (&vf->vf_bytes[dst * stride]);
265 }
266 
267 /*
268  * bit_to_pix4 is for 4-bit frame buffers.  It will write one output byte
269  * for each 2 bits of input bitmap.  It inverts the input bits before
270  * doing the output translation, for reverse video.
271  *
272  * Assuming foreground is 0001 and background is 0000...
273  * An input data byte of 0x53 will output the bit pattern
274  * 00000001 00000001 00000000 00010001.
275  */
276 
277 void
278 font_bit_to_pix4(
279     struct font *f,
280     uint8_t *dest,
281     uint32_t c,
282     uint8_t fg_color,
283     uint8_t bg_color)
284 {
285 	uint32_t row;
286 	int	byte;
287 	int	i;
288 	const uint8_t *cp, *ul;
289 	uint8_t	data;
290 	uint8_t	nibblett;
291 	int	bytes_wide;
292 
293 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
294 		ul = font_lookup(f, 0x0332);	/* combining low line */
295 	else
296 		ul = NULL;
297 
298 	cp = font_lookup(f, c);
299 	bytes_wide = (f->vf_width + 7) / 8;
300 
301 	for (row = 0; row < f->vf_height; row++) {
302 		for (byte = 0; byte < bytes_wide; byte++) {
303 			if (ul == NULL)
304 				data = *cp++;
305 			else
306 				data = *cp++ | *ul++;
307 			for (i = 0; i < 4; i++) {
308 				nibblett = (data >> ((3-i) * 2)) & 0x3;
309 				switch (nibblett) {
310 				case 0x0:
311 					*dest++ = bg_color << 4 | bg_color;
312 					break;
313 				case 0x1:
314 					*dest++ = bg_color << 4 | fg_color;
315 					break;
316 				case 0x2:
317 					*dest++ = fg_color << 4 | bg_color;
318 					break;
319 				case 0x3:
320 					*dest++ = fg_color << 4 | fg_color;
321 					break;
322 				}
323 			}
324 		}
325 	}
326 }
327 
328 /*
329  * bit_to_pix8 is for 8-bit frame buffers.  It will write one output byte
330  * for each bit of input bitmap.  It inverts the input bits before
331  * doing the output translation, for reverse video.
332  *
333  * Assuming foreground is 00000001 and background is 00000000...
334  * An input data byte of 0x53 will output the bit pattern
335  * 0000000 000000001 00000000 00000001 00000000 00000000 00000001 00000001.
336  */
337 
338 void
339 font_bit_to_pix8(
340     struct font *f,
341     uint8_t *dest,
342     uint32_t c,
343     uint8_t fg_color,
344     uint8_t bg_color)
345 {
346 	uint32_t row;
347 	int	byte;
348 	int	i;
349 	const uint8_t *cp, *ul;
350 	uint8_t	data;
351 	int	bytes_wide;
352 	uint8_t	mask;
353 	int	bitsleft, nbits;
354 
355 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
356 		ul = font_lookup(f, 0x0332);	/* combining low line */
357 	else
358 		ul = NULL;
359 
360 	cp = font_lookup(f, c);
361 	bytes_wide = (f->vf_width + 7) / 8;
362 
363 	for (row = 0; row < f->vf_height; row++) {
364 		bitsleft = f->vf_width;
365 		for (byte = 0; byte < bytes_wide; byte++) {
366 			if (ul == NULL)
367 				data = *cp++;
368 			else
369 				data = *cp++ | *ul++;
370 			mask = 0x80;
371 			nbits = MIN(8, bitsleft);
372 			bitsleft -= nbits;
373 			for (i = 0; i < nbits; i++) {
374 				*dest++ = (data & mask ? fg_color: bg_color);
375 				mask = mask >> 1;
376 			}
377 		}
378 	}
379 }
380 
381 /*
382  * bit_to_pix16 is for 16-bit frame buffers.  It will write two output bytes
383  * for each bit of input bitmap.  It inverts the input bits before
384  * doing the output translation, for reverse video.
385  *
386  * Assuming foreground is 11111111 11111111
387  * and background is 00000000 00000000
388  * An input data byte of 0x53 will output the bit pattern
389  *
390  * 00000000 00000000
391  * 11111111 11111111
392  * 00000000 00000000
393  * 11111111 11111111
394  * 00000000 00000000
395  * 00000000 00000000
396  * 11111111 11111111
397  * 11111111 11111111
398  *
399  */
400 
401 void
402 font_bit_to_pix16(
403     struct font *f,
404     uint16_t *dest,
405     uint32_t c,
406     uint16_t fg_color16,
407     uint16_t bg_color16)
408 {
409 	uint32_t row;
410 	int	byte;
411 	int	i;
412 	const uint8_t *cp, *ul;
413 	uint16_t data, d;
414 	int	bytes_wide;
415 	int	bitsleft, nbits;
416 
417 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
418 		ul = font_lookup(f, 0x0332);	/* combining low line */
419 	else
420 		ul = NULL;
421 
422 	cp = font_lookup(f, c);
423 	bytes_wide = (f->vf_width + 7) / 8;
424 
425 	for (row = 0; row < f->vf_height; row++) {
426 		bitsleft = f->vf_width;
427 		for (byte = 0; byte < bytes_wide; byte++) {
428 			if (ul == NULL)
429 				data = *cp++;
430 			else
431 				data = *cp++ | *ul++;
432 			nbits = MIN(8, bitsleft);
433 			bitsleft -= nbits;
434 			for (i = 0; i < nbits; i++) {
435 				d = ((data << i) & 0x80 ?
436 				    fg_color16 : bg_color16);
437 				*dest++ = d;
438 			}
439 		}
440 	}
441 }
442 
443 /*
444  * bit_to_pix24 is for 24-bit frame buffers.  It will write three output bytes
445  * for each bit of input bitmap.  It inverts the input bits before
446  * doing the output translation, for reverse video.
447  *
448  * Assuming foreground is 11111111 11111111 11111111
449  * and background is 00000000 00000000 00000000
450  * An input data byte of 0x53 will output the bit pattern
451  *
452  * 00000000 00000000 00000000
453  * 11111111 11111111 11111111
454  * 00000000 00000000 00000000
455  * 11111111 11111111 11111111
456  * 00000000 00000000 00000000
457  * 00000000 00000000 00000000
458  * 11111111 11111111 11111111
459  * 11111111 11111111 11111111
460  *
461  */
462 
463 void
464 font_bit_to_pix24(
465     struct font *f,
466     uint8_t *dest,
467     uint32_t c,
468     uint32_t fg_color32,
469     uint32_t bg_color32)
470 {
471 	uint32_t row;
472 	int	byte;
473 	int	i;
474 	const uint8_t *cp, *ul;
475 	uint32_t data, d;
476 	int	bytes_wide;
477 	int	bitsleft, nbits;
478 
479 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
480 		ul = font_lookup(f, 0x0332);	/* combining low line */
481 	else
482 		ul = NULL;
483 
484 	cp = font_lookup(f, c);
485 	bytes_wide = (f->vf_width + 7) / 8;
486 
487 	for (row = 0; row < f->vf_height; row++) {
488 		bitsleft = f->vf_width;
489 		for (byte = 0; byte < bytes_wide; byte++) {
490 			if (ul == NULL)
491 				data = *cp++;
492 			else
493 				data = *cp++ | *ul++;
494 
495 			nbits = MIN(8, bitsleft);
496 			bitsleft -= nbits;
497 			for (i = 0; i < nbits; i++) {
498 				d = ((data << i) & 0x80 ?
499 				    fg_color32 : bg_color32);
500 				*dest++ = d & 0xff;
501 				*dest++ = (d >> 8) & 0xff;
502 				*dest++ = (d >> 16) & 0xff;
503 			}
504 		}
505 	}
506 }
507 
508 /*
509  * bit_to_pix32 is for 32-bit frame buffers.  It will write four output bytes
510  * for each bit of input bitmap.  It inverts the input bits before
511  * doing the output translation, for reverse video.  Note that each
512  * 24-bit RGB value is finally stored in a 32-bit unsigned int, with the
513  * high-order byte set to zero.
514  *
515  * Assuming foreground is 00000000 11111111 11111111 11111111
516  * and background is 00000000 00000000 00000000 00000000
517  * An input data byte of 0x53 will output the bit pattern
518  *
519  * 00000000 00000000 00000000 00000000
520  * 00000000 11111111 11111111 11111111
521  * 00000000 00000000 00000000 00000000
522  * 00000000 11111111 11111111 11111111
523  * 00000000 00000000 00000000 00000000
524  * 00000000 00000000 00000000 00000000
525  * 00000000 11111111 11111111 11111111
526  * 00000000 11111111 11111111 11111111
527  *
528  */
529 
530 void
531 font_bit_to_pix32(
532     struct font *f,
533     uint32_t *dest,
534     uint32_t c,
535     uint32_t fg_color32,
536     uint32_t bg_color32)
537 {
538 	uint32_t row;
539 	int	byte;
540 	int	i;
541 	const uint8_t *cp, *ul;
542 	uint32_t data;
543 	int	bytes_wide;
544 	int	bitsleft, nbits;
545 
546 	if (TEM_CHAR_ATTR(c) & TEM_ATTR_UNDERLINE)
547 		ul = font_lookup(f, 0x0332);	/* combining low line */
548 	else
549 		ul = NULL;
550 
551 	cp = font_lookup(f, c);
552 	bytes_wide = (f->vf_width + 7) / 8;
553 
554 	for (row = 0; row < f->vf_height; row++) {
555 		bitsleft = f->vf_width;
556 		for (byte = 0; byte < bytes_wide; byte++) {
557 			if (ul == NULL)
558 				data = *cp++;
559 			else
560 				data = *cp++ | *ul++;
561 			nbits = MIN(8, bitsleft);
562 			bitsleft -= nbits;
563 			for (i = 0; i < nbits; i++) {
564 				*dest++ = ((data << i) & 0x80 ?
565 				    fg_color32 : bg_color32);
566 			}
567 		}
568 	}
569 }
570