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