xref: /linux/lib/fonts/fonts.c (revision afac4c66d1aa6396ce44d94fe895d7b61e085fd4) !
1 /*
2  * `Soft' font definitions
3  *
4  *    Created 1995 by Geert Uytterhoeven
5  *    Rewritten 1998 by Martin Mares <mj@ucw.cz>
6  *
7  *	2001 - Documented with DocBook
8  *	- Brad Douglas <brad@neruo.com>
9  *
10  * This file is subject to the terms and conditions of the GNU General Public
11  * License.  See the file COPYING in the main directory of this archive
12  * for more details.
13  */
14 
15 #include <linux/container_of.h>
16 #include <linux/kd.h>
17 #include <linux/module.h>
18 #include <linux/overflow.h>
19 #include <linux/slab.h>
20 #include <linux/string.h>
21 #include <linux/types.h>
22 
23 #if defined(__mc68000__)
24 #include <asm/setup.h>
25 #endif
26 
27 #include "font.h"
28 
29 #define console_font_pitch(font) font_glyph_pitch((font)->width)
30 
31 /*
32  * Helpers for font_data_t
33  */
34 
35 /* Extra word getters */
36 #define REFCOUNT(fd)	(((int *)(fd))[-1])
37 #define FNTSIZE(fd)	(((int *)(fd))[-2])
38 #define FNTSUM(fd)	(((int *)(fd))[-4])
39 
40 static struct font_data *to_font_data_struct(font_data_t *fd)
41 {
42 	return container_of(fd, struct font_data, data[0]);
43 }
44 
45 static bool font_data_is_internal(font_data_t *fd)
46 {
47 	return !REFCOUNT(fd); /* internal fonts have no reference counting */
48 }
49 
50 static void font_data_free(font_data_t *fd)
51 {
52 	kfree(to_font_data_struct(fd));
53 }
54 
55 /**
56  * font_data_import - Allocates and initializes font data from user space
57  * @font: A font from user space
58  * @vpitch: The size of a single glyph in @font in bytes
59  * @calc_csum: An optional helper to calculate a chechsum
60  *
61  * Font data from user space must be translated to the kernel's format. The
62  * font's glyph geometry and data is provided in @font. The parameter @vpitch
63  * gives the number of bytes per glyph, including trailing bytes.
64  *
65  * The parameter @calc_csum is optional. Fbcon passes crc32() to calculate the
66  * font data's checksum.
67  *
68  * Returns:
69  * Newly initialized font data on success, or a pointer-encoded errno value otherwise.
70  */
71 font_data_t *font_data_import(const struct console_font *font, unsigned int vpitch,
72 			      u32 (*calc_csum)(u32, const void *, size_t))
73 {
74 	unsigned int pitch = console_font_pitch(font);
75 	unsigned int h = font->height;
76 	unsigned int charcount = font->charcount;
77 	const unsigned char *data = font->data;
78 	u32 csum = 0;
79 	struct font_data *font_data;
80 	int size, alloc_size;
81 	unsigned int i;
82 	font_data_t *fd;
83 
84 	/* Check for integer overflow in font-size calculation */
85 	if (check_mul_overflow(h, pitch, &size) ||
86 	    check_mul_overflow(size, charcount, &size))
87 		return ERR_PTR(-EINVAL);
88 
89 	/* Check for overflow in allocation size calculation */
90 	if (check_add_overflow(sizeof(*font_data), size, &alloc_size))
91 		return ERR_PTR(-EINVAL);
92 
93 	font_data = kmalloc(alloc_size, GFP_USER);
94 	if (!font_data)
95 		return ERR_PTR(-ENOMEM);
96 	memset(font_data->extra, 0, sizeof(font_data->extra));
97 
98 	for (i = 0; i < charcount; ++i)
99 		memcpy(font_data->data + i * h * pitch, data + i * vpitch * pitch, h * pitch);
100 
101 	if (calc_csum)
102 		csum = calc_csum(0, font_data->data, size);
103 
104 	fd = font_data->data;
105 	REFCOUNT(fd) = 1; /* start with reference acquired */
106 	FNTSIZE(fd) = size;
107 	FNTSUM(fd) = csum;
108 
109 	return fd;
110 }
111 EXPORT_SYMBOL_GPL(font_data_import);
112 
113 /**
114  * font_data_get - Acquires a reference on font data
115  * @fd: Font data
116  *
117  * Font data from user space is reference counted. The helper
118  * font_data_get() increases the reference counter by one. Invoke
119  * font_data_put() to release the reference.
120  *
121  * Internal font data is located in read-only memory. In this case
122  * the helper returns success without modifying the counter field.
123  * It is still required to call font_data_put() on internal font data.
124  */
125 void font_data_get(font_data_t *fd)
126 {
127 	if (font_data_is_internal(fd))
128 		return; /* never ref static data */
129 
130 	if (WARN_ON(!REFCOUNT(fd)))
131 		return; /* should never be 0 */
132 	++REFCOUNT(fd);
133 }
134 EXPORT_SYMBOL_GPL(font_data_get);
135 
136 /**
137  * font_data_put - Release a reference on font data
138  * @fd: Font data
139  *
140  * Font data from user space is reference counted. The helper
141  * font_data_put() decreases the reference counter by one. If this was
142  * the final reference, it frees the allocated memory.
143  *
144  * Internal font data is located in read-only memory. In this case
145  * the helper returns success without modifying the counter field.
146  *
147  * Returns:
148  * True if the font data's memory buffer has been freed, false otherwise.
149  */
150 bool font_data_put(font_data_t *fd)
151 {
152 	unsigned int count;
153 
154 	if (font_data_is_internal(fd))
155 		return false; /* never unref static data */
156 
157 	if (WARN_ON(!REFCOUNT(fd)))
158 		return false; /* should never be 0 */
159 
160 	count = --REFCOUNT(fd);
161 	if (!count)
162 		font_data_free(fd);
163 
164 	return !count;
165 }
166 EXPORT_SYMBOL_GPL(font_data_put);
167 
168 /**
169  * font_data_size - Return size of the font data in bytes
170  * @fd: Font data
171  *
172  * Returns:
173  * The number of bytes in the given font data.
174  */
175 unsigned int font_data_size(font_data_t *fd)
176 {
177 	return FNTSIZE(fd);
178 }
179 EXPORT_SYMBOL_GPL(font_data_size);
180 
181 /**
182  * font_data_is_equal - Compares font data for equality
183  * @lhs: Left-hand side font data
184  * @rhs: Right-hand-size font data
185  *
186  * Font data is equal if is constain the same sequence of values. The
187  * helper also use the checksum, if both arguments contain it. Font data
188  * coming from different origins, internal or from user space, is never
189  * equal. Allowing this would break reference counting.
190  *
191  * Returns:
192  * True if the given font data is equal, false otherwise.
193  */
194 bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
195 {
196 	if (font_data_is_internal(lhs) != font_data_is_internal(rhs))
197 		return false;
198 	if (font_data_size(lhs) != font_data_size(rhs))
199 		return false;
200 	if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs))
201 		return false;
202 
203 	return !memcmp(lhs, rhs, FNTSIZE(lhs));
204 }
205 EXPORT_SYMBOL_GPL(font_data_is_equal);
206 
207 /**
208  * font_data_export - Stores font data for user space
209  * @fd: Font data
210  * @font: A font for user space
211  * @vpitch: The size of a single glyph in @font in bytes
212  *
213  * Store the font data given in @fd to the font in @font. Values and
214  * pointers in @font are pre-initialized. This helper mostly checks some
215  * corner cases and translates glyph sizes according to the value given
216  * @vpitch.
217  *
218  * Returns:
219  * 0 on success, or a negative errno code otherwise.
220  */
221 int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch)
222 {
223 	const unsigned char *font_data = font_data_buf(fd);
224 	unsigned char *data = font->data;
225 	unsigned int pitch = console_font_pitch(font);
226 	unsigned int glyphsize, i;
227 
228 	if (!font->width || !font->height || !font->charcount || !font->data)
229 		return 0;
230 
231 	glyphsize = font->height * pitch;
232 
233 	if (font->charcount * glyphsize > font_data_size(fd))
234 		return -EINVAL;
235 
236 	for (i = 0; i < font->charcount; i++) {
237 		memcpy(data, font_data, glyphsize);
238 		memset(data + glyphsize, 0, pitch * vpitch - glyphsize);
239 		data += pitch * vpitch;
240 		font_data += glyphsize;
241 	}
242 
243 	return 0;
244 }
245 EXPORT_SYMBOL_GPL(font_data_export);
246 
247 /*
248  * Font lookup
249  */
250 
251 static const struct font_desc *fonts[] = {
252 #ifdef CONFIG_FONT_8x8
253 	&font_vga_8x8,
254 #endif
255 #ifdef CONFIG_FONT_8x16
256 	&font_vga_8x16,
257 #endif
258 #ifdef CONFIG_FONT_6x11
259 	&font_vga_6x11,
260 #endif
261 #ifdef CONFIG_FONT_7x14
262 	&font_7x14,
263 #endif
264 #ifdef CONFIG_FONT_SUN8x16
265 	&font_sun_8x16,
266 #endif
267 #ifdef CONFIG_FONT_SUN12x22
268 	&font_sun_12x22,
269 #endif
270 #ifdef CONFIG_FONT_10x18
271 	&font_10x18,
272 #endif
273 #ifdef CONFIG_FONT_ACORN_8x8
274 	&font_acorn_8x8,
275 #endif
276 #ifdef CONFIG_FONT_PEARL_8x8
277 	&font_pearl_8x8,
278 #endif
279 #ifdef CONFIG_FONT_MINI_4x6
280 	&font_mini_4x6,
281 #endif
282 #ifdef CONFIG_FONT_6x10
283 	&font_6x10,
284 #endif
285 #ifdef CONFIG_FONT_TER10x18
286 	&font_ter_10x18,
287 #endif
288 #ifdef CONFIG_FONT_TER16x32
289 	&font_ter_16x32,
290 #endif
291 #ifdef CONFIG_FONT_6x8
292 	&font_6x8,
293 #endif
294 };
295 
296 #define num_fonts ARRAY_SIZE(fonts)
297 
298 #ifdef NO_FONTS
299 #error No fonts configured.
300 #endif
301 
302 
303 /**
304  *	find_font - find a font
305  *	@name: string name of a font
306  *
307  *	Find a specified font with string name @name.
308  *
309  *	Returns %NULL if no font found, or a pointer to the
310  *	specified font.
311  *
312  */
313 const struct font_desc *find_font(const char *name)
314 {
315 	unsigned int i;
316 
317 	BUILD_BUG_ON(!num_fonts);
318 	for (i = 0; i < num_fonts; i++)
319 		if (!strcmp(fonts[i]->name, name))
320 			return fonts[i];
321 	return NULL;
322 }
323 EXPORT_SYMBOL(find_font);
324 
325 
326 /**
327  *	get_default_font - get default font
328  *	@xres: screen size of X
329  *	@yres: screen size of Y
330  *	@font_w: bit array of supported widths (1 - FB_MAX_BLIT_WIDTH)
331  *	@font_h: bit array of supported heights (1 - FB_MAX_BLIT_HEIGHT)
332  *
333  *	Get the default font for a specified screen size.
334  *	Dimensions are in pixels.
335  *
336  *	font_w or font_h being NULL means all values are supported.
337  *
338  *	Returns %NULL if no font is found, or a pointer to the
339  *	chosen font.
340  *
341  */
342 const struct font_desc *get_default_font(int xres, int yres,
343 					 unsigned long *font_w,
344 					 unsigned long *font_h)
345 {
346 	int i, c, cc, res;
347 	const struct font_desc *f, *g;
348 
349 	g = NULL;
350 	cc = -10000;
351 	for (i = 0; i < num_fonts; i++) {
352 		f = fonts[i];
353 		c = f->pref;
354 #if defined(__mc68000__)
355 #ifdef CONFIG_FONT_PEARL_8x8
356 		if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
357 			c = 100;
358 #endif
359 #ifdef CONFIG_FONT_6x11
360 		if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
361 			c = 100;
362 #endif
363 #endif
364 		if ((yres < 400) == (f->height <= 8))
365 			c += 1000;
366 
367 		/* prefer a bigger font for high resolution */
368 		res = (xres / f->width) * (yres / f->height) / 1000;
369 		if (res > 20)
370 			c += 20 - res;
371 
372 		if ((!font_w || test_bit(f->width - 1, font_w)) &&
373 		    (!font_h || test_bit(f->height - 1, font_h)))
374 			c += 1000;
375 
376 		if (c > cc) {
377 			cc = c;
378 			g = f;
379 		}
380 	}
381 	return g;
382 }
383 EXPORT_SYMBOL(get_default_font);
384 
385 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
386 MODULE_DESCRIPTION("Console Fonts");
387 MODULE_LICENSE("GPL");
388