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