xref: /netbsd-src/sys/dev/wsfont/wsfont.c (revision 53b02e147d4ed531c0d2a5ca9b3e8026ba3e99b5)
1 /* 	$NetBSD: wsfont.c,v 1.77 2021/12/24 18:12:58 jmcneill Exp $	*/
2 
3 /*-
4  * Copyright (c) 1999, 2000, 2001, 2002 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Andrew Doran.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: wsfont.c,v 1.77 2021/12/24 18:12:58 jmcneill Exp $");
34 
35 #include "opt_wsfont.h"
36 
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/time.h>
40 #include <sys/malloc.h>
41 #include <sys/queue.h>
42 
43 #include <dev/wscons/wsdisplayvar.h>
44 #include <dev/wscons/wsconsio.h>
45 #include <dev/wsfont/wsfont.h>
46 
47 #include "wsfont_glue.h"	/* NRASOPS_ROTATION */
48 
49 #undef HAVE_FONT
50 
51 #ifdef FONT_QVSS8x15
52 #define HAVE_FONT 1
53 #include <dev/wsfont/qvss8x15.h>
54 #endif
55 
56 #ifdef FONT_GALLANT12x22
57 #define HAVE_FONT 1
58 #include <dev/wsfont/gallant12x22.h>
59 #endif
60 
61 #ifdef FONT_LUCIDA16x29
62 #define HAVE_FONT 1
63 #include <dev/wsfont/lucida16x29.h>
64 #endif
65 
66 #ifdef FONT_VT220L8x8
67 #define HAVE_FONT 1
68 #include <dev/wsfont/vt220l8x8.h>
69 #endif
70 
71 #ifdef FONT_VT220L8x10
72 #define HAVE_FONT 1
73 #include <dev/wsfont/vt220l8x10.h>
74 #endif
75 
76 #ifdef FONT_VT220L8x16
77 #define HAVE_FONT 1
78 #include <dev/wsfont/vt220l8x16.h>
79 #endif
80 
81 #ifdef FONT_VT220ISO8x8
82 #define HAVE_FONT 1
83 #include <dev/wsfont/vt220iso8x8.h>
84 #endif
85 
86 #ifdef FONT_VT220ISO8x16
87 #define HAVE_FONT 1
88 #include <dev/wsfont/vt220iso8x16.h>
89 #endif
90 
91 #ifdef FONT_VT220KOI8x10_KOI8_R
92 #define HAVE_FONT 1
93 #include <dev/wsfont/vt220koi8x10.h>
94 #endif
95 
96 #ifdef FONT_VT220KOI8x10_KOI8_U
97 #define HAVE_FONT 1
98 #define KOI8_U
99 #include <dev/wsfont/vt220koi8x10.h>
100 #undef KOI8_U
101 #endif
102 
103 #ifdef FONT_SONY8x16
104 #define HAVE_FONT 1
105 #include <dev/wsfont/sony8x16.h>
106 #endif
107 
108 #ifdef FONT_SONY12x24
109 #define HAVE_FONT 1
110 #include <dev/wsfont/sony12x24.h>
111 #endif
112 
113 #ifdef FONT_OMRON12x20
114 #define HAVE_FONT 1
115 #include <dev/wsfont/omron12x20.h>
116 #endif
117 
118 #ifdef FONT_GLASS10x19
119 #define HAVE_FONT 1
120 #include <dev/wsfont/glass10x19.h>
121 #endif
122 
123 #ifdef FONT_GLASS10x25
124 #define HAVE_FONT 1
125 #include <dev/wsfont/glass10x25.h>
126 #endif
127 
128 #ifdef FONT_DEJAVU_SANS_MONO12x22
129 #define HAVE_FONT 1
130 #include <dev/wsfont/DejaVu_Sans_Mono_12x22.h>
131 #endif
132 
133 #ifdef FONT_DROID_SANS_MONO9x18
134 #define HAVE_FONT 1
135 #include <dev/wsfont/Droid_Sans_Mono_9x18.h>
136 #endif
137 
138 #ifdef FONT_DROID_SANS_MONO10x20
139 #define HAVE_FONT 1
140 #include <dev/wsfont/Droid_Sans_Mono_10x20.h>
141 #endif
142 
143 #ifdef FONT_DROID_SANS_MONO12x22
144 #define HAVE_FONT 1
145 #include <dev/wsfont/Droid_Sans_Mono_12x22.h>
146 #endif
147 
148 #ifdef FONT_DROID_SANS_MONO19x36
149 #define HAVE_FONT 1
150 #include <dev/wsfont/Droid_Sans_Mono_19x36.h>
151 #endif
152 
153 #ifdef FONT_GO_MONO12x23
154 #define HAVE_FONT 1
155 #include <dev/wsfont/Go_Mono_12x23.h>
156 #endif
157 
158 #ifdef FONT_SPLEEN5x8
159 #define HAVE_FONT 1
160 #include <dev/wsfont/spleen5x8.h>
161 #endif
162 
163 #ifdef FONT_SPLEEN6x12
164 #define HAVE_FONT 1
165 #include <dev/wsfont/spleen6x12.h>
166 #endif
167 
168 #ifdef FONT_SPLEEN8x16
169 #define HAVE_FONT 1
170 #include <dev/wsfont/spleen8x16.h>
171 #endif
172 
173 #ifdef FONT_SPLEEN12x24
174 #define HAVE_FONT 1
175 #include <dev/wsfont/spleen12x24.h>
176 #endif
177 
178 #ifdef FONT_SPLEEN16x32
179 #define HAVE_FONT 1
180 #include <dev/wsfont/spleen16x32.h>
181 #endif
182 
183 #ifdef FONT_SPLEEN32x64
184 #define HAVE_FONT 1
185 #include <dev/wsfont/spleen32x64.h>
186 #endif
187 
188 #ifdef FONT_LIBERATION_MONO12x21
189 #define HAVE_FONT 1
190 #include <dev/wsfont/Liberation_Mono_12x21.h>
191 #endif
192 
193 #ifdef FONT_BOLD16x32
194 #define HAVE_FONT 1
195 #include <dev/wsfont/bold16x32.h>
196 #endif
197 
198 /* Make sure we always have at least one bitmap font. */
199 #ifndef HAVE_FONT
200 #define HAVE_FONT 1
201 #define FONT_BOLD8x16 1
202 #endif
203 
204 #ifdef FONT_BOLD8x16
205 #include <dev/wsfont/bold8x16.h>
206 #endif
207 
208 #define	WSFONT_IDENT_MASK	0xffffff00
209 #define	WSFONT_IDENT_SHIFT	8
210 #define	WSFONT_BITO_MASK	0x000000f0
211 #define	WSFONT_BITO_SHIFT	4
212 #define	WSFONT_BYTEO_MASK	0x0000000f
213 #define	WSFONT_BYTEO_SHIFT	0
214 
215 #define WSFONT_BUILTIN	0x01	/* In wsfont.c */
216 #define WSFONT_STATIC	0x02	/* Font structures not malloc()ed */
217 #define WSFONT_COPY	0x04	/* Copy of existing font in table */
218 
219 /* Placeholder struct used for linked list */
220 struct font {
221 	TAILQ_ENTRY(font) chain;
222 	struct	wsdisplay_font *font;
223 	u_int	lockcount;
224 	u_int	cookie;
225 	u_int	flags;
226 };
227 
228 /* Our list of built-in fonts */
229 static struct font builtin_fonts[] = {
230 #ifdef FONT_BOLD8x16
231 	{ { NULL, NULL }, &bold8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN  },
232 #endif
233 #ifdef FONT_BOLD16x32
234 	{ { NULL, NULL }, &bold16x32, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN  },
235 #endif
236 #ifdef FONT_GALLANT12x22
237 	{ { NULL, NULL }, &gallant12x22, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
238 #endif
239 #ifdef FONT_LUCIDA16x29
240 	{ { NULL, NULL }, &lucida16x29, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
241 #endif
242 #ifdef FONT_QVSS8x15
243 	{ { NULL, NULL }, &qvss8x15, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
244 #endif
245 #ifdef FONT_VT220L8x8
246 	{ { NULL, NULL }, &vt220l8x8, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
247 #endif
248 #ifdef FONT_VT220L8x10
249 	{ { NULL, NULL }, &vt220l8x10, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
250 #endif
251 #ifdef FONT_VT220L8x16
252 	{ { NULL, NULL }, &vt220l8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
253 #endif
254 #ifdef FONT_VT220ISO8x8
255 	{ { NULL, NULL }, &vt220iso8x8, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
256 #endif
257 #ifdef FONT_VT220ISO8x16
258 	{ { NULL, NULL }, &vt220iso8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
259 #endif
260 #ifdef FONT_VT220KOI8x10_KOI8_R
261 	{ { NULL, NULL }, &vt220kr8x10, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
262 #endif
263 #ifdef FONT_VT220KOI8x10_KOI8_U
264 	{ { NULL, NULL }, &vt220ku8x10, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
265 #endif
266 #ifdef FONT_SONY8x16
267 	{ { NULL, NULL }, &sony8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
268 #endif
269 #ifdef FONT_SONY12x24
270 	{ { NULL, NULL }, &sony12x24, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
271 #endif
272 #ifdef FONT_OMRON12x20
273 	{ { NULL, NULL }, &omron12x20, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
274 #endif
275 #ifdef FONT_GLASS10x19
276 	{ { NULL, NULL }, &Glass_TTY_VT220_10x19, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
277 #endif
278 #ifdef FONT_GLASS10x25
279 	{ { NULL, NULL }, &Glass_TTY_VT220_10x25, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
280 #endif
281 #ifdef FONT_DEJAVU_SANS_MONO12x22
282 	{ { NULL, NULL }, &DejaVu_Sans_Mono_12x22, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
283 #endif
284 #ifdef FONT_DROID_SANS_MONO9x18
285 	{ { NULL, NULL }, &Droid_Sans_Mono_9x18, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
286 #endif
287 #ifdef FONT_DROID_SANS_MONO10x20
288 	{ { NULL, NULL }, &Droid_Sans_Mono_10x20, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
289 #endif
290 #ifdef FONT_DROID_SANS_MONO12x22
291 	{ { NULL, NULL }, &Droid_Sans_Mono_12x22, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
292 #endif
293 #ifdef FONT_DROID_SANS_MONO19x36
294 	{ { NULL, NULL }, &Droid_Sans_Mono_19x36, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
295 #endif
296 #ifdef FONT_GO_MONO12x23
297 	{ { NULL, NULL }, &Go_Mono_12x23, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
298 #endif
299 #ifdef FONT_SPLEEN5x8
300 	{ { NULL, NULL }, &spleen5x8, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
301 #endif
302 #ifdef FONT_SPLEEN6x12
303 	{ { NULL, NULL }, &spleen6x12, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
304 #endif
305 #ifdef FONT_SPLEEN8x16
306 	{ { NULL, NULL }, &spleen8x16, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
307 #endif
308 #ifdef FONT_SPLEEN12x24
309 	{ { NULL, NULL }, &spleen12x24, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
310 #endif
311 #ifdef FONT_SPLEEN16x32
312 	{ { NULL, NULL }, &spleen16x32, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
313 #endif
314 #ifdef FONT_SPLEEN32x64
315 	{ { NULL, NULL }, &spleen32x64, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
316 #endif
317 #ifdef FONT_LIBERATION_MONO12x21
318 	{ { NULL, NULL }, &Liberation_Mono_12x21, 0, 0, WSFONT_STATIC | WSFONT_BUILTIN },
319 #endif
320 	{ { NULL, NULL }, NULL, 0, 0, 0 },
321 };
322 
323 static TAILQ_HEAD(,font)	list;
324 static int	ident;
325 
326 /* Reverse the bit order in a byte */
327 static const u_char reverse[256] = {
328 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
329 	0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
330 	0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
331 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
332 	0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
333 	0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
334 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
335 	0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
336 	0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
337 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
338 	0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
339 	0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
340 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
341 	0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
342 	0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
343 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
344 	0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
345 	0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
346 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
347 	0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
348 	0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
349 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
350 	0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
351 	0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
352 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
353 	0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
354 	0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
355 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
356 	0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
357 	0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
358 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
359 	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
360 };
361 
362 static struct	font *wsfont_find0(int, int);
363 static struct	font *wsfont_add0(struct wsdisplay_font *, int);
364 static void	wsfont_revbit(struct wsdisplay_font *);
365 static void	wsfont_revbyte(struct wsdisplay_font *);
366 
367 int
368 wsfont_make_cookie(int cident, int bito, int byteo)
369 {
370 
371 	return ((cident & WSFONT_IDENT_MASK) |
372 	    (bito << WSFONT_BITO_SHIFT) |
373 	    (byteo << WSFONT_BYTEO_SHIFT));
374 }
375 
376 static void
377 wsfont_revbit(struct wsdisplay_font *font)
378 {
379 	u_char *p, *m;
380 
381 	p = (u_char *)font->data;
382 	m = p + font->stride * font->numchars * font->fontheight;
383 
384 	for (; p < m; p++)
385 		*p = reverse[*p];
386 }
387 
388 static void
389 wsfont_revbyte(struct wsdisplay_font *font)
390 {
391 	int x, l, r, nr;
392 	u_char *rp;
393 
394 	if (font->stride == 1)
395 		return;
396 
397 	rp = (u_char *)font->data;
398 	nr = font->numchars * font->fontheight;
399 
400 	while (nr--) {
401 		l = 0;
402 		r = font->stride - 1;
403 
404 		while (l < r) {
405 			x = rp[l];
406 			rp[l] = rp[r];
407 			rp[r] = x;
408 			l++, r--;
409 		}
410 
411 		rp += font->stride;
412 	}
413 }
414 
415 void
416 wsfont_enum(void (*cb)(const char *, int, int, int))
417 {
418 	struct wsdisplay_font *f;
419 	struct font *ent;
420 
421 	TAILQ_FOREACH(ent, &list, chain) {
422 		f = ent->font;
423 		cb(f->name, f->fontwidth, f->fontheight, f->stride);
424 	}
425 }
426 
427 #if NRASOPS_ROTATION > 0
428 
429 static struct wsdisplay_font *
430 wsfont_rotate_internal(struct wsdisplay_font *font, int rotate)
431 {
432 	struct wsdisplay_font *newfont;
433 	char *newname, *newdata;
434 	u_char *ch, *newch, *p, *newp;
435 	int namelen, newstride, n, h, w;
436 	u_char bit;
437 	bool alpha = FONT_IS_ALPHA(font), cw = (rotate == WSFONT_ROTATE_CW);
438 
439 	/* Duplicate the existing font... */
440 	newfont = malloc(sizeof(*font), M_DEVBUF, M_WAITOK);
441 
442 	*newfont = *font;
443 
444 	namelen = strlen(font->name) + 4;
445 	newname = malloc(namelen, M_DEVBUF, M_WAITOK);
446 	strlcpy(newname, font->name, namelen);
447 	strlcat(newname, cw ? "cw" : "ccw", namelen);
448 	newfont->name = newname;
449 
450 	/* Allocate a buffer big enough for the rotated font. */
451 	newstride = alpha ? font->fontheight : howmany(font->fontheight, 8);
452 	newdata = malloc(newstride * font->fontwidth * font->numchars,
453 	    M_DEVBUF, M_WAITOK|M_ZERO);
454 
455 #define	BYTE_OFFSET(x, alpha)	((alpha) ? (x) : (x) / 8)
456 #define	BIT_FROM_LEFT(x)	__BIT(7 - ((x) % 8))
457 #define	BIT_FROM_RIGHT(x)	__BIT((x) % 8)
458 
459 	/* Rotate the font a pixel at a time. */
460 	for (n = 0; n < font->numchars; n++) {
461 		ch = (u_char *)font->data +
462 		    (n * font->stride * font->fontheight);
463 		newch = newdata +
464 		    (n * newstride * font->fontwidth);
465 		for (h = 0; h < font->fontheight; h++) {
466 			for (w = 0; w < font->fontwidth; w++) {
467 				p = ch + (h * font->stride) +
468 				    BYTE_OFFSET(w, alpha);
469 				if (cw) {
470 					/* Rotate clockwise. */
471 					newp = newch +
472 					    (w * newstride) +
473 					    (newstride - 1 -
474 						BYTE_OFFSET(h, alpha));
475 					bit = BIT_FROM_RIGHT(h);
476 				} else {
477 					/* Rotate counter-clockwise. */
478 					newp = newch +
479 					    ((font->fontwidth - 1 - w) *
480 						newstride) +
481 					    BYTE_OFFSET(h, alpha);
482 					bit = BIT_FROM_LEFT(h);
483 				}
484 				if (alpha) {
485 					*newp = *p;
486 				} else {
487 					if (*p & BIT_FROM_LEFT(w))
488 						*newp |= bit;
489 				}
490 			}
491 		}
492 	}
493 
494 #undef	BYTE_OFFSET
495 #undef	BIT_FROM_LEFT
496 #undef	BIT_FROM_RIGHT
497 
498 	newfont->data = newdata;
499 
500 	/* Update font sizes. */
501 	newfont->stride = newstride;
502 	newfont->fontwidth = font->fontheight;
503 	newfont->fontheight = font->fontwidth;
504 
505 	if (wsfont_add(newfont, 0) != 0) {
506 		/*
507 		 * If we seem to have rotated this font already, drop the
508 		 * new one...
509 		 */
510 		free(newdata, M_DEVBUF);
511 		free(newfont, M_DEVBUF);
512 		newfont = NULL;
513 	}
514 
515 	return (newfont);
516 }
517 
518 int
519 wsfont_rotate(int cookie, int rotate)
520 {
521 	int s, ncookie;
522 	struct wsdisplay_font *font;
523 	struct font *origfont;
524 
525 	s = splhigh();
526 	origfont = wsfont_find0(cookie, 0xffffffff);
527 	splx(s);
528 
529 	if (origfont == NULL)
530 		return (-1);
531 
532 	switch (rotate) {
533 	case WSFONT_ROTATE_CW:
534 	case WSFONT_ROTATE_CCW:
535 		font = wsfont_rotate_internal(origfont->font, rotate);
536 		if (font == NULL)
537 			return (-1);
538 		break;
539 
540 	case WSFONT_ROTATE_UD:
541 	default:
542 		return (-1);
543 	}
544 
545 	ncookie = wsfont_find(font->name, font->fontwidth, font->fontheight,
546 	    font->stride, 0, 0, WSFONT_FIND_ALL);
547 
548 	return (ncookie);
549 }
550 
551 #endif	/* NRASOPS_ROTATION */
552 
553 void
554 wsfont_init(void)
555 {
556 	struct font *ent;
557 	static int again;
558 	int i;
559 
560 	if (again != 0)
561 		return;
562 	again = 1;
563 
564 	TAILQ_INIT(&list);
565 	ent = builtin_fonts;
566 
567 	for (i = 0; builtin_fonts[i].font != NULL; i++, ent++) {
568 		ident += (1 << WSFONT_IDENT_SHIFT);
569 		ent->cookie = wsfont_make_cookie(ident,
570 		    ent->font->bitorder, ent->font->byteorder);
571 		TAILQ_INSERT_TAIL(&list, ent, chain);
572 	}
573 }
574 
575 static struct font *
576 wsfont_find0(int cookie, int mask)
577 {
578 	struct font *ent;
579 
580 	TAILQ_FOREACH(ent, &list, chain) {
581 		if ((ent->cookie & mask) == (cookie & mask))
582 			return (ent);
583 	}
584 
585 	return (NULL);
586 }
587 
588 int
589 wsfont_matches(struct wsdisplay_font *font, const char *name,
590 	       int width, int height, int stride, int flags)
591 {
592 	int score = 20000;
593 
594 	/* first weed out fonts the caller doesn't claim support for */
595 	if (FONT_IS_ALPHA(font)) {
596 		if (flags & WSFONT_PREFER_ALPHA)
597 			score++;
598 		if ((flags & WSFONT_FIND_ALPHA) == 0)
599 			return 0;
600 	} else {
601 		if ((flags & WSFONT_FIND_BITMAP) == 0)
602 			return 0;
603 	}
604 
605 	if (height != 0 && font->fontheight != height)
606 		return (0);
607 
608 	if (width != 0) {
609 		if ((flags & WSFONT_FIND_BESTWIDTH) == 0) {
610 			if (font->fontwidth != width)
611 				return (0);
612 		} else {
613 			if (font->fontwidth > width) {
614 				score -= uimin(font->fontwidth - width, 9999);
615 				if ((flags & WSFONT_PREFER_WIDE) == 0) {
616 					score -= 10000;
617 				}
618 			} else {
619 				score -= uimin(width - font->fontwidth, 9999);
620 				if ((flags & WSFONT_PREFER_WIDE) != 0) {
621 					score -= 10000;
622 				}
623 			}
624 		}
625 	}
626 
627 	if (stride != 0 && font->stride != stride)
628 		return (0);
629 
630 	if (name != NULL && strcmp(font->name, name) != 0)
631 		return (0);
632 
633 	return (score);
634 }
635 
636 int
637 wsfont_find(const char *name, int width, int height, int stride, int bito, int byteo, int flags)
638 {
639 	struct font *ent, *bestent = NULL;
640 	int score, bestscore = 0;
641 
642 	TAILQ_FOREACH(ent, &list, chain) {
643 		score = wsfont_matches(ent->font, name,
644 				width, height, stride, flags);
645 		if (score > bestscore) {
646 			bestscore = score;
647 			bestent = ent;
648 		}
649 	}
650 
651 	if (bestent != NULL)
652 		return (wsfont_make_cookie(bestent->cookie, bito, byteo));
653 
654 	return (-1);
655 }
656 
657 void
658 wsfont_walk(void (*matchfunc)(struct wsdisplay_font *, void *, int), void *cookie)
659 {
660 	struct font *ent;
661 
662 	TAILQ_FOREACH(ent, &list, chain) {
663 		matchfunc(ent->font, cookie, ent->cookie);
664 	}
665 }
666 
667 static struct font *
668 wsfont_add0(struct wsdisplay_font *font, int copy)
669 {
670 	struct font *ent;
671 	size_t size;
672 
673 	ent = malloc(sizeof(struct font), M_DEVBUF, M_WAITOK | M_ZERO);
674 
675 	/* Is this font statically allocated? */
676 	if (!copy) {
677 		ent->font = font;
678 		ent->flags = WSFONT_STATIC;
679 	} else {
680 		void *data;
681 		char *name;
682 
683 		ent->font = malloc(sizeof(struct wsdisplay_font), M_DEVBUF,
684 		    M_WAITOK);
685 		memcpy(ent->font, font, sizeof(*ent->font));
686 
687 		size = font->fontheight * font->numchars * font->stride;
688 		data = malloc(size, M_DEVBUF, M_WAITOK);
689 		memcpy(data, font->data, size);
690 		ent->font->data = data;
691 
692 		name = malloc(strlen(font->name) + 1, M_DEVBUF, M_WAITOK);
693 		strlcpy(name, font->name, strlen(font->name) + 1);
694 		ent->font->name = name;
695 	}
696 
697 	TAILQ_INSERT_TAIL(&list, ent, chain);
698 	return (ent);
699 }
700 
701 int
702 wsfont_add(struct wsdisplay_font *font, int copy)
703 {
704 	struct font *ent;
705 
706 	/* Don't allow exact duplicates */
707 	if (wsfont_find(font->name, font->fontwidth, font->fontheight,
708 	    font->stride, 0, 0, WSFONT_FIND_ALL) >= 0)
709 		return (EEXIST);
710 
711 	ent = wsfont_add0(font, copy);
712 
713 	ident += (1 << WSFONT_IDENT_SHIFT);
714 	ent->cookie = wsfont_make_cookie(ident, font->bitorder,
715 	    font->byteorder);
716 
717 	return (0);
718 }
719 
720 int
721 wsfont_remove(int cookie)
722 {
723 	struct font *ent;
724 
725 	if ((ent = wsfont_find0(cookie, 0xffffffff)) == NULL)
726 		return (ENOENT);
727 
728 	if ((ent->flags & WSFONT_BUILTIN) != 0 || ent->lockcount != 0)
729 		return (EBUSY);
730 
731 	if ((ent->flags & WSFONT_STATIC) == 0) {
732 		free(ent->font->data, M_DEVBUF);
733 		free(__UNCONST(ent->font->name), M_DEVBUF); /*XXXUNCONST*/
734 		free(ent->font, M_DEVBUF);
735 	}
736 
737 	TAILQ_REMOVE(&list, ent, chain);
738 	free(ent, M_DEVBUF);
739 
740 	return (0);
741 }
742 
743 int
744 wsfont_lock(int cookie, struct wsdisplay_font **ptr)
745 {
746 	struct font *ent, *neu;
747 	int bito, byteo;
748 
749 	if ((ent = wsfont_find0(cookie, 0xffffffff)) == NULL) {
750 		if ((ent = wsfont_find0(cookie, WSFONT_IDENT_MASK)) == NULL)
751 			return (ENOENT);
752 
753 		bito = (cookie & WSFONT_BITO_MASK) >> WSFONT_BITO_SHIFT;
754 		byteo = (cookie & WSFONT_BYTEO_MASK) >> WSFONT_BYTEO_SHIFT;
755 
756 		if (ent->lockcount != 0) {
757 			neu = wsfont_add0(ent->font, 1);
758 			neu->flags |= WSFONT_COPY;
759 
760 			aprint_debug("wsfont: font '%s' bito %d byteo %d "
761 			    "copied to bito %d byteo %d\n",
762 			    ent->font->name,
763 			    ent->font->bitorder, ent->font->byteorder,
764 			    bito, byteo);
765 
766 			ent = neu;
767 		}
768 
769 		if (bito && bito != ent->font->bitorder) {
770 			wsfont_revbit(ent->font);
771 			ent->font->bitorder = bito;
772 		}
773 
774 		if (byteo && byteo != ent->font->byteorder) {
775 			wsfont_revbyte(ent->font);
776 			ent->font->byteorder = byteo;
777 		}
778 
779 		ent->cookie = cookie;
780 	}
781 
782 	ent->lockcount++;
783 	*ptr = ent->font;
784 	return (0);
785 }
786 
787 int
788 wsfont_unlock(int cookie)
789 {
790 	struct font *ent;
791 
792 	if ((ent = wsfont_find0(cookie, 0xffffffff)) == NULL)
793 		return (ENOENT);
794 
795 	if (ent->lockcount == 0)
796 		panic("wsfont_unlock: font not locked");
797 
798 	if (--ent->lockcount == 0 && (ent->flags & WSFONT_COPY) != 0)
799 		wsfont_remove(cookie);
800 
801 	return (0);
802 }
803 
804 /*
805  * Unicode to font encoding mappings
806  */
807 
808 /*
809  * To save memory, font encoding tables use a two level lookup.  First the
810  * high byte of the Unicode is used to lookup the level 2 table, then the
811  * low byte indexes that table.  Level 2 tables that are not needed are
812  * omitted (NULL), and both level 1 and level 2 tables have base and size
813  * attributes to keep their size down.
814  */
815 
816 struct wsfont_level1_glyphmap {
817 	const struct	wsfont_level2_glyphmap **level2;
818 	int	base;	/* High byte for first level2 entry	*/
819 	int	size;	/* Number of level2 entries		*/
820 };
821 
822 struct wsfont_level2_glyphmap {
823 	int	base;	/* Low byte for first character		*/
824 	int	size;	/* Number of characters			*/
825 	const void	*chars;	/* Pointer to character number entries  */
826 	int	width;	/* Size of each entry in bytes (1,2,4)  */
827 };
828 
829 #define null16			\
830 	NULL, NULL, NULL, NULL,	\
831 	NULL, NULL, NULL, NULL,	\
832 	NULL, NULL, NULL, NULL,	\
833 	NULL, NULL, NULL, NULL
834 
835 /*
836  * IBM 437 maps
837  */
838 
839 static const u_int8_t ibm437_chars_0[] = {
840 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
841 	16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
842 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
843 	48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
844 	64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
845 	80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
846 	96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,
847 	112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
848 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
849 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
850 	255,173,155,156, 0, 157, 0,  0,  0,  0, 166,174,170, 0,  0,  0,
851 	 0, 241,253, 0,  0,  0,  0, 249, 0,  0, 167,175,172,171, 0, 168,
852 	 0,  0,  0,  0, 142,143,146,128, 0, 144, 0,  0,  0,  0,  0,  0,
853 	 0, 165, 0,  0,  0,  0, 153, 0,  0,  0,  0,  0, 154, 0,  0,  0,
854 	133,160,131, 0, 132,134,145,135,138,130,136,137,141,161,140,139,
855 	 0, 164,149,162,147, 0, 148,246, 0, 151,163,150,129, 0,  0, 152
856 };
857 
858 static const u_int8_t ibm437_chars_1[] = {
859 	159
860 };
861 
862 static const u_int8_t ibm437_chars_3[] = {
863 	226, 0,  0,  0,  0, 233, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
864 	228, 0,  0, 232, 0,  0, 234, 0,  0,  0,  0,  0,  0,  0, 224,225,
865 	 0, 235,238, 0,  0,  0,  0,  0,  0, 230, 0,  0,  0, 227, 0,  0,
866 	229,231
867 };
868 
869 static const u_int8_t ibm437_chars_32[] = {
870 	252, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
871 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
872 	 0,  0,  0,  0,  0,  0,  0,  0, 158
873 };
874 
875 static const u_int8_t ibm437_chars_34[] = {
876 	237, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
877 	 0,  0,  0, 248,250,251, 0,  0,  0, 236, 0,  0,  0,  0,  0,  0,
878 	 0,  0,  0,  0, 239, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
879 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
880 	 0,  0,  0, 247, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
881 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,240,  0,  0,243,
882 	242
883 };
884 
885 static const u_int8_t ibm437_chars_35[] = {
886 	169, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
887 	244,245
888 };
889 
890 static const u_int8_t ibm437_chars_37[] = {
891 	196,205,179,186, 0,  0,  0,  0,  0,  0,  0,  0, 218,213,214,201,
892 	191,184,183,187,192,212,211,200,217,190,189,188,195,198, 0,  0,
893 	199, 0,  0, 204,180,181, 0,  0, 182, 0,  0, 185,194, 0,  0, 209,
894 	210, 0,  0, 203,193, 0,  0, 207,208, 0,  0, 202,197, 0,  0, 216,
895 	 0,  0, 215, 0,  0,  0,  0,  0,  0,  0,  0, 206, 0,  0,  0,  0,
896 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
897 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
898 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
899 	223, 0,  0,  0, 220, 0,  0,  0, 219, 0,  0,  0, 221, 0,  0,  0,
900 	222,176,177,178, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
901 	254
902 };
903 
904 static const struct wsfont_level2_glyphmap ibm437_level2_0 =
905     { 0, 256, ibm437_chars_0, 1 };
906 
907 static const struct wsfont_level2_glyphmap ibm437_level2_1 =
908     { 146, 1, ibm437_chars_1, 1 };
909 
910 static const struct wsfont_level2_glyphmap ibm437_level2_3 =
911     { 147, 50, ibm437_chars_3, 1 };
912 
913 static const struct wsfont_level2_glyphmap ibm437_level2_32 =
914     { 127, 41, ibm437_chars_32, 1 };
915 
916 static const struct wsfont_level2_glyphmap ibm437_level2_34 =
917     { 5, 97, ibm437_chars_34, 1 };
918 
919 static const struct wsfont_level2_glyphmap ibm437_level2_35 =
920     { 16, 18, ibm437_chars_35, 1 };
921 
922 static const struct wsfont_level2_glyphmap ibm437_level2_37 =
923     { 0, 161, ibm437_chars_37, 1 };
924 
925 static const struct wsfont_level2_glyphmap *ibm437_level1[] = {
926 	&ibm437_level2_0, &ibm437_level2_1, NULL, &ibm437_level2_3,
927 	NULL, NULL, NULL, NULL,
928 	NULL, NULL, NULL, NULL,
929 	NULL, NULL, NULL, NULL,
930 	NULL, NULL, NULL, NULL,
931 	NULL, NULL, NULL, NULL,
932 	NULL, NULL, NULL, NULL,
933 	NULL, NULL, NULL, NULL,
934 	&ibm437_level2_32, NULL, &ibm437_level2_34, &ibm437_level2_35,
935 	NULL, &ibm437_level2_37
936 };
937 
938 /*
939  * ISO-8859-7 maps
940  */
941 static const u_int8_t iso7_chars_0[] = {
942 	 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
943 	16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
944 	32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
945 	48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
946 	64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
947 	80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
948 	96, 97, 98, 99, 100,101,102,103,104,105,106,107,108,109,110,111,
949 	112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
950 	128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
951 	144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
952 	160, 0,  0, 163, 0,  0, 166,167,168,169, 0, 171,172,173, 0,  0,
953 	176,177,178,179,180, 0,  0, 183, 0,  0,  0, 187, 0, 189
954 };
955 
956 static const u_int8_t iso7_chars_3[] = {
957 	182, 0, 184,185,186, 0, 188, 0, 190,191,192,193,194,195,196,197,
958 	198,199,200,201,202,203,204,205,206,207,208,209, 0, 211,212,213,
959 	214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,
960 	230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,
961 	246,247,248,249,250,251,252,253,254, 0,  0,  0,  0,  0,  0,  0,
962 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
963 	 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 181
964 };
965 
966 /*
967  * map all variants of the box drawing characters to the same basic shapes for
968  * now, encoded like this:
969  *
970  *    1
971  *    1
972  * 888 222
973  *    4
974  *    4
975  *
976  * so an upright line would be 0x05
977  */
978 #define FL |WSFONT_FLAG_OPT
979 static const u_int32_t netbsd_boxes[] = {
980 /*00*/ 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL, 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL,
981 /*08*/ 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL, 0x06 FL, 0x06 FL, 0x06 FL, 0x06 FL,
982 /*10*/ 0x0c FL, 0x0c FL, 0x0c FL, 0x0c FL, 0x03 FL, 0x03 FL, 0x03 FL, 0x03 FL,
983 /*18*/ 0x09 FL, 0x09 FL, 0x09 FL, 0x09 FL, 0x07 FL, 0x07 FL, 0x07 FL, 0x07 FL,
984 /*20*/ 0x07 FL, 0x07 FL, 0x07 FL, 0x07 FL, 0x0d FL, 0x0d FL, 0x0d FL, 0x0d FL,
985 /*28*/ 0x0d FL, 0x0d FL, 0x0d FL, 0x0d FL, 0x0e FL, 0x0e FL, 0x0e FL, 0x0e FL,
986 /*30*/ 0x0e FL, 0x0e FL, 0x0e FL, 0x0e FL, 0x0b FL, 0x0b FL, 0x0b FL, 0x0b FL,
987 /*38*/ 0x0b FL, 0x0b FL, 0x0b FL, 0x0b FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL,
988 /*40*/ 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL,
989 /*48*/ 0x0f FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x0a FL, 0x0a FL, 0x05 FL, 0x05 FL,
990 /*50*/ 0x0a FL, 0x05 FL, 0x06 FL, 0x06 FL, 0x06 FL, 0x0c FL, 0x0c FL, 0x0c FL,
991 /*58*/ 0x03 FL, 0x03 FL, 0x03 FL, 0x09 FL, 0x09 FL, 0x09 FL, 0x07 FL, 0x07 FL,
992 /*60*/ 0x07 FL, 0x0d FL, 0x0d FL, 0x0d FL, 0x0e FL, 0x0e FL, 0x0e FL, 0x0b FL,
993 /*68*/ 0x0b FL, 0x0b FL, 0x0f FL, 0x0f FL, 0x0f FL, 0x06 FL, 0x0c FL, 0x09 FL,
994 /*70*/ 0x03 FL,    0 FL,    0 FL,    0 FL, 0x08 FL, 0x01 FL, 0x02 FL, 0x04 FL,
995 /*78*/ 0x08 FL, 0x01 FL, 0x02 FL, 0x04 FL, 0x0a FL, 0x05 FL, 0x0a FL, 0x05 FL
996 };
997 #undef FL
998 
999 static const u_int8_t iso7_chars_32[] = {
1000 	175, 0,  0,  0,  0, 162, 0, 161
1001 };
1002 
1003 static const struct wsfont_level2_glyphmap iso7_level2_0 =
1004     { 0, 190, iso7_chars_0, 1 };
1005 
1006 static const struct wsfont_level2_glyphmap iso7_level2_3 =
1007     { 134, 111, iso7_chars_3, 1 };
1008 
1009 static const struct wsfont_level2_glyphmap iso7_level2_32 =
1010     { 20, 8, iso7_chars_32, 1 };
1011 
1012 static const struct wsfont_level2_glyphmap netbsd_box_drawing =
1013     { 0, 128, netbsd_boxes, 4 };
1014 
1015 static const struct wsfont_level2_glyphmap *iso7_level1[] = {
1016 	&iso7_level2_0, NULL, NULL, &iso7_level2_3,
1017 	NULL, NULL, NULL, NULL,
1018 	NULL, NULL, NULL, NULL,
1019 	NULL, NULL, NULL, NULL,
1020 	NULL, NULL, NULL, NULL,
1021 	NULL, NULL, NULL, NULL,
1022 	NULL, NULL, NULL, NULL,
1023 	NULL, NULL, NULL, NULL,
1024 	&iso7_level2_32, NULL, NULL, NULL,
1025 	NULL, &netbsd_box_drawing
1026 };
1027 
1028 static const struct wsfont_level2_glyphmap *iso_level1[] = {
1029 	NULL, NULL, NULL, NULL,
1030 	NULL, NULL, NULL, NULL,
1031 	NULL, NULL, NULL, NULL,
1032 	NULL, NULL, NULL, NULL,
1033 	NULL, NULL, NULL, NULL,
1034 	NULL, NULL, NULL, NULL,
1035 	NULL, NULL, NULL, NULL,
1036 	NULL, NULL, NULL, NULL,
1037 	NULL, NULL, NULL, NULL,
1038 	NULL, &netbsd_box_drawing
1039 };
1040 
1041 static const struct wsfont_level1_glyphmap encodings[] = {
1042 	{ iso_level1, 0, 0x26 },	/* WSDISPLAY_FONTENC_ISO */
1043 	{ ibm437_level1, 0, 38 },	/* WSDISPLAY_FONTENC_IBM */
1044 	{ NULL, 0, 0 },			/* WSDISPLAY_FONTENC_PCVT */
1045 	{ iso7_level1, 0, 0x26 },	/* WSDISPLAY_FONTENC_ISO7 */
1046 };
1047 
1048 #define MAX_ENCODING (sizeof(encodings) / sizeof(encodings[0]))
1049 
1050 /*
1051  * Remap Unicode character to glyph
1052  */
1053 int
1054 wsfont_map_unichar(struct wsdisplay_font *font, int c)
1055 {
1056 	const struct wsfont_level1_glyphmap *map1;
1057 	const struct wsfont_level2_glyphmap *map2;
1058 	int hi, lo;
1059 
1060 	if (font->encoding < 0 || font->encoding >= MAX_ENCODING)
1061 		return (-1);
1062 
1063 	hi = (c >> 8);
1064 	lo = c & 255;
1065 	map1 = &encodings[font->encoding];
1066 
1067 	if (hi < map1->base || hi >= map1->base + map1->size)
1068 		return (-1);
1069 
1070 	map2 = map1->level2[hi - map1->base];
1071 
1072 	/* so we don't need an identical level 2 table for hi == 0 */
1073 	if (hi == 0 && font->encoding == WSDISPLAY_FONTENC_ISO)
1074 		return lo;
1075 
1076 	if (map2 == NULL || lo < map2->base || lo >= map2->base + map2->size)
1077 		return (-1);
1078 
1079 	lo -= map2->base;
1080 
1081 	switch(map2->width) {
1082 	case 1:
1083 		c = (((const u_int8_t *)map2->chars)[lo]);
1084 		break;
1085 	case 2:
1086 		c = (((const u_int16_t *)map2->chars)[lo]);
1087 		break;
1088 	case 4:
1089 		c = (((const u_int32_t *)map2->chars)[lo]);
1090 		break;
1091 	}
1092 
1093 	if (c == 0 && lo != 0)
1094 		return (-1);
1095 
1096 	return (c);
1097 }
1098