xref: /freebsd/sys/dev/vt/vt_font.c (revision 27cf7d04ef5416dc7fcbf43bc8147463b0d87848)
1*27cf7d04SAleksandr Rybalko /*-
2*27cf7d04SAleksandr Rybalko  * Copyright (c) 2009 The FreeBSD Foundation
3*27cf7d04SAleksandr Rybalko  * All rights reserved.
4*27cf7d04SAleksandr Rybalko  *
5*27cf7d04SAleksandr Rybalko  * This software was developed by Ed Schouten under sponsorship from the
6*27cf7d04SAleksandr Rybalko  * FreeBSD Foundation.
7*27cf7d04SAleksandr Rybalko  *
8*27cf7d04SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
9*27cf7d04SAleksandr Rybalko  * modification, are permitted provided that the following conditions
10*27cf7d04SAleksandr Rybalko  * are met:
11*27cf7d04SAleksandr Rybalko  * 1. Redistributions of source code must retain the above copyright
12*27cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer.
13*27cf7d04SAleksandr Rybalko  * 2. Redistributions in binary form must reproduce the above copyright
14*27cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer in the
15*27cf7d04SAleksandr Rybalko  *    documentation and/or other materials provided with the distribution.
16*27cf7d04SAleksandr Rybalko  *
17*27cf7d04SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18*27cf7d04SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19*27cf7d04SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*27cf7d04SAleksandr Rybalko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21*27cf7d04SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*27cf7d04SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23*27cf7d04SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24*27cf7d04SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25*27cf7d04SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26*27cf7d04SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27*27cf7d04SAleksandr Rybalko  * SUCH DAMAGE.
28*27cf7d04SAleksandr Rybalko  */
29*27cf7d04SAleksandr Rybalko 
30*27cf7d04SAleksandr Rybalko #include <sys/cdefs.h>
31*27cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$");
32*27cf7d04SAleksandr Rybalko 
33*27cf7d04SAleksandr Rybalko #include <sys/param.h>
34*27cf7d04SAleksandr Rybalko #include <sys/kernel.h>
35*27cf7d04SAleksandr Rybalko #include <sys/malloc.h>
36*27cf7d04SAleksandr Rybalko #include <sys/refcount.h>
37*27cf7d04SAleksandr Rybalko #include <sys/systm.h>
38*27cf7d04SAleksandr Rybalko 
39*27cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
40*27cf7d04SAleksandr Rybalko 
41*27cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font");
42*27cf7d04SAleksandr Rybalko 
43*27cf7d04SAleksandr Rybalko /* Some limits to prevent abnormal fonts from being loaded. */
44*27cf7d04SAleksandr Rybalko #define	VTFONT_MAXMAPPINGS	1024
45*27cf7d04SAleksandr Rybalko #define	VTFONT_MAXGLYPHSIZE	262144
46*27cf7d04SAleksandr Rybalko #define	VTFONT_MAXDIMENSION	128
47*27cf7d04SAleksandr Rybalko 
48*27cf7d04SAleksandr Rybalko static uint16_t
49*27cf7d04SAleksandr Rybalko vtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src)
50*27cf7d04SAleksandr Rybalko {
51*27cf7d04SAleksandr Rybalko 	int min, mid, max;
52*27cf7d04SAleksandr Rybalko 
53*27cf7d04SAleksandr Rybalko 	min = 0;
54*27cf7d04SAleksandr Rybalko 	max = len - 1;
55*27cf7d04SAleksandr Rybalko 
56*27cf7d04SAleksandr Rybalko 	/* Empty font map. */
57*27cf7d04SAleksandr Rybalko 	if (len == 0)
58*27cf7d04SAleksandr Rybalko 		return (0);
59*27cf7d04SAleksandr Rybalko 	/* Character below minimal entry. */
60*27cf7d04SAleksandr Rybalko 	if (src < map[0].vfm_src)
61*27cf7d04SAleksandr Rybalko 		return (0);
62*27cf7d04SAleksandr Rybalko 	/* Optimization: ASCII characters occur very often. */
63*27cf7d04SAleksandr Rybalko 	if (src <= map[0].vfm_src + map[0].vfm_len)
64*27cf7d04SAleksandr Rybalko 		return (src - map[0].vfm_src + map[0].vfm_dst);
65*27cf7d04SAleksandr Rybalko 	/* Character above maximum entry. */
66*27cf7d04SAleksandr Rybalko 	if (src > map[max].vfm_src + map[max].vfm_len)
67*27cf7d04SAleksandr Rybalko 		return (0);
68*27cf7d04SAleksandr Rybalko 
69*27cf7d04SAleksandr Rybalko 	/* Binary search. */
70*27cf7d04SAleksandr Rybalko 	while (max >= min) {
71*27cf7d04SAleksandr Rybalko 		mid = (min + max) / 2;
72*27cf7d04SAleksandr Rybalko 		if (src < map[mid].vfm_src)
73*27cf7d04SAleksandr Rybalko 			max = mid - 1;
74*27cf7d04SAleksandr Rybalko 		else if (src > map[mid].vfm_src + map[mid].vfm_len)
75*27cf7d04SAleksandr Rybalko 			min = mid + 1;
76*27cf7d04SAleksandr Rybalko 		else
77*27cf7d04SAleksandr Rybalko 			return (src - map[mid].vfm_src + map[mid].vfm_dst);
78*27cf7d04SAleksandr Rybalko 	}
79*27cf7d04SAleksandr Rybalko 
80*27cf7d04SAleksandr Rybalko 	return (0);
81*27cf7d04SAleksandr Rybalko }
82*27cf7d04SAleksandr Rybalko 
83*27cf7d04SAleksandr Rybalko const uint8_t *
84*27cf7d04SAleksandr Rybalko vtfont_lookup(const struct vt_font *vf, term_char_t c)
85*27cf7d04SAleksandr Rybalko {
86*27cf7d04SAleksandr Rybalko 	uint32_t src;
87*27cf7d04SAleksandr Rybalko 	uint16_t dst;
88*27cf7d04SAleksandr Rybalko 	size_t stride;
89*27cf7d04SAleksandr Rybalko 
90*27cf7d04SAleksandr Rybalko 	src = TCHAR_CHARACTER(c);
91*27cf7d04SAleksandr Rybalko 	if (TCHAR_FORMAT(c) & TF_BOLD) {
92*27cf7d04SAleksandr Rybalko 		dst = vtfont_bisearch(vf->vf_bold, vf->vf_bold_length, src);
93*27cf7d04SAleksandr Rybalko 		if (dst != 0)
94*27cf7d04SAleksandr Rybalko 			goto found;
95*27cf7d04SAleksandr Rybalko 	}
96*27cf7d04SAleksandr Rybalko 	dst = vtfont_bisearch(vf->vf_normal, vf->vf_normal_length, src);
97*27cf7d04SAleksandr Rybalko 
98*27cf7d04SAleksandr Rybalko found:
99*27cf7d04SAleksandr Rybalko 	stride = howmany(vf->vf_width, 8) * vf->vf_height;
100*27cf7d04SAleksandr Rybalko 	return (&vf->vf_bytes[dst * stride]);
101*27cf7d04SAleksandr Rybalko }
102*27cf7d04SAleksandr Rybalko 
103*27cf7d04SAleksandr Rybalko struct vt_font *
104*27cf7d04SAleksandr Rybalko vtfont_ref(struct vt_font *vf)
105*27cf7d04SAleksandr Rybalko {
106*27cf7d04SAleksandr Rybalko 
107*27cf7d04SAleksandr Rybalko 	refcount_acquire(&vf->vf_refcount);
108*27cf7d04SAleksandr Rybalko 	return (vf);
109*27cf7d04SAleksandr Rybalko }
110*27cf7d04SAleksandr Rybalko 
111*27cf7d04SAleksandr Rybalko void
112*27cf7d04SAleksandr Rybalko vtfont_unref(struct vt_font *vf)
113*27cf7d04SAleksandr Rybalko {
114*27cf7d04SAleksandr Rybalko 
115*27cf7d04SAleksandr Rybalko 	if (refcount_release(&vf->vf_refcount)) {
116*27cf7d04SAleksandr Rybalko 		free(vf->vf_normal, M_VTFONT);
117*27cf7d04SAleksandr Rybalko 		free(vf->vf_bold, M_VTFONT);
118*27cf7d04SAleksandr Rybalko 		free(vf->vf_bytes, M_VTFONT);
119*27cf7d04SAleksandr Rybalko 		free(vf, M_VTFONT);
120*27cf7d04SAleksandr Rybalko 	}
121*27cf7d04SAleksandr Rybalko }
122*27cf7d04SAleksandr Rybalko 
123*27cf7d04SAleksandr Rybalko static int
124*27cf7d04SAleksandr Rybalko vtfont_validate_map(struct vt_font_map *vfm, unsigned int length,
125*27cf7d04SAleksandr Rybalko     unsigned int nglyphs)
126*27cf7d04SAleksandr Rybalko {
127*27cf7d04SAleksandr Rybalko 	unsigned int i, last = 0;
128*27cf7d04SAleksandr Rybalko 
129*27cf7d04SAleksandr Rybalko 	for (i = 0; i < length; i++) {
130*27cf7d04SAleksandr Rybalko 		/* Not ordered. */
131*27cf7d04SAleksandr Rybalko 		if (i > 0 && vfm[i].vfm_src <= last)
132*27cf7d04SAleksandr Rybalko 			return (EINVAL);
133*27cf7d04SAleksandr Rybalko 		/*
134*27cf7d04SAleksandr Rybalko 		 * Destination extends amount of glyphs.
135*27cf7d04SAleksandr Rybalko 		 */
136*27cf7d04SAleksandr Rybalko 		if (vfm[i].vfm_dst >= nglyphs ||
137*27cf7d04SAleksandr Rybalko 		    vfm[i].vfm_dst + vfm[i].vfm_len >= nglyphs)
138*27cf7d04SAleksandr Rybalko 			return (EINVAL);
139*27cf7d04SAleksandr Rybalko 		last = vfm[i].vfm_src + vfm[i].vfm_len;
140*27cf7d04SAleksandr Rybalko 	}
141*27cf7d04SAleksandr Rybalko 
142*27cf7d04SAleksandr Rybalko 	return (0);
143*27cf7d04SAleksandr Rybalko }
144*27cf7d04SAleksandr Rybalko 
145*27cf7d04SAleksandr Rybalko int
146*27cf7d04SAleksandr Rybalko vtfont_load(vfnt_t *f, struct vt_font **ret)
147*27cf7d04SAleksandr Rybalko {
148*27cf7d04SAleksandr Rybalko 	size_t glyphsize;
149*27cf7d04SAleksandr Rybalko 	struct vt_font *vf;
150*27cf7d04SAleksandr Rybalko 	int error;
151*27cf7d04SAleksandr Rybalko 
152*27cf7d04SAleksandr Rybalko 	/* Make sure the dimensions are valid. */
153*27cf7d04SAleksandr Rybalko 	if (f->width < 1 || f->height < 1)
154*27cf7d04SAleksandr Rybalko 		return (EINVAL);
155*27cf7d04SAleksandr Rybalko 	if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION)
156*27cf7d04SAleksandr Rybalko 		return (E2BIG);
157*27cf7d04SAleksandr Rybalko 
158*27cf7d04SAleksandr Rybalko 	/* Not too many mappings. */
159*27cf7d04SAleksandr Rybalko 	if (f->nnormal > VTFONT_MAXMAPPINGS || f->nbold > VTFONT_MAXMAPPINGS)
160*27cf7d04SAleksandr Rybalko 		return (E2BIG);
161*27cf7d04SAleksandr Rybalko 
162*27cf7d04SAleksandr Rybalko 	/* Character 0 must always be present. */
163*27cf7d04SAleksandr Rybalko 	if (f->nglyphs < 1)
164*27cf7d04SAleksandr Rybalko 		return (EINVAL);
165*27cf7d04SAleksandr Rybalko 
166*27cf7d04SAleksandr Rybalko 	glyphsize = howmany(f->width, 8) * f->height * f->nglyphs;
167*27cf7d04SAleksandr Rybalko 	if (glyphsize > VTFONT_MAXGLYPHSIZE)
168*27cf7d04SAleksandr Rybalko 		return (E2BIG);
169*27cf7d04SAleksandr Rybalko 
170*27cf7d04SAleksandr Rybalko 	/* Allocate new font structure. */
171*27cf7d04SAleksandr Rybalko 	vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK);
172*27cf7d04SAleksandr Rybalko 	vf->vf_normal = malloc(f->nnormal * sizeof(struct vt_font_map),
173*27cf7d04SAleksandr Rybalko 	    M_VTFONT, M_WAITOK);
174*27cf7d04SAleksandr Rybalko 	vf->vf_bold = malloc(f->nbold * sizeof(struct vt_font_map),
175*27cf7d04SAleksandr Rybalko 	    M_VTFONT, M_WAITOK);
176*27cf7d04SAleksandr Rybalko 	vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK);
177*27cf7d04SAleksandr Rybalko 	vf->vf_height = f->height;
178*27cf7d04SAleksandr Rybalko 	vf->vf_width = f->width;
179*27cf7d04SAleksandr Rybalko 	vf->vf_normal_length = f->nnormal;
180*27cf7d04SAleksandr Rybalko 	vf->vf_bold_length = f->nbold;
181*27cf7d04SAleksandr Rybalko 	vf->vf_refcount = 1;
182*27cf7d04SAleksandr Rybalko 
183*27cf7d04SAleksandr Rybalko 	/* Copy in data. */
184*27cf7d04SAleksandr Rybalko 	error = copyin(f->normal, vf->vf_normal,
185*27cf7d04SAleksandr Rybalko 	    vf->vf_normal_length * sizeof(struct vt_font_map));
186*27cf7d04SAleksandr Rybalko 	if (error)
187*27cf7d04SAleksandr Rybalko 		goto bad;
188*27cf7d04SAleksandr Rybalko 	error = copyin(f->bold, vf->vf_bold,
189*27cf7d04SAleksandr Rybalko 	    vf->vf_bold_length * sizeof(struct vt_font_map));
190*27cf7d04SAleksandr Rybalko 	if (error)
191*27cf7d04SAleksandr Rybalko 		goto bad;
192*27cf7d04SAleksandr Rybalko 	error = copyin(f->glyphs, vf->vf_bytes, glyphsize);
193*27cf7d04SAleksandr Rybalko 	if (error)
194*27cf7d04SAleksandr Rybalko 		goto bad;
195*27cf7d04SAleksandr Rybalko 
196*27cf7d04SAleksandr Rybalko 	/* Validate mappings. */
197*27cf7d04SAleksandr Rybalko 	error = vtfont_validate_map(vf->vf_normal, vf->vf_normal_length,
198*27cf7d04SAleksandr Rybalko 	    f->nglyphs);
199*27cf7d04SAleksandr Rybalko 	if (error)
200*27cf7d04SAleksandr Rybalko 		goto bad;
201*27cf7d04SAleksandr Rybalko 	error = vtfont_validate_map(vf->vf_bold, vf->vf_bold_length,
202*27cf7d04SAleksandr Rybalko 	    f->nglyphs);
203*27cf7d04SAleksandr Rybalko 	if (error)
204*27cf7d04SAleksandr Rybalko 		goto bad;
205*27cf7d04SAleksandr Rybalko 
206*27cf7d04SAleksandr Rybalko 	/* Success. */
207*27cf7d04SAleksandr Rybalko 	*ret = vf;
208*27cf7d04SAleksandr Rybalko 	return (0);
209*27cf7d04SAleksandr Rybalko 
210*27cf7d04SAleksandr Rybalko bad:	vtfont_unref(vf);
211*27cf7d04SAleksandr Rybalko 	return (error);
212*27cf7d04SAleksandr Rybalko }
213