xref: /linux/lib/fonts/fonts.c (revision 4e69c1856bfd9ffb7e9d335a25842fa211628929)
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 static unsigned int font_data_num_glyphs(font_data_t *fd, unsigned int width, unsigned int height)
182 {
183 	return font_data_size(fd) / font_glyph_size(width, height);
184 }
185 
186 /**
187  * font_data_glyph_buf() - Returns the glyph for a specific character as raw bytes
188  * @fd: The font data
189  * @width: The glyph width in bits per scanline
190  * @vpitch: The number of scanlines per glyph
191  * @c: The character
192  *
193  * Glyphs start at fixed intervals within the font data. font_data_glyph_buf()
194  * returns the glyph shape of the specified character. If no such glyph
195  * exists in the font, it returns NULL.
196  *
197  * Returns:
198  * The character's raw glyph shape, or NULL if no glyph exists for the character. The
199  * provided buffer is read-only.
200  */
201 const unsigned char *font_data_glyph_buf(font_data_t *fd,
202 					 unsigned int width, unsigned int vpitch,
203 					 unsigned int c)
204 {
205 	if (c >= font_data_num_glyphs(fd, width, vpitch))
206 		return NULL;
207 
208 	return font_data_buf(fd) + font_glyph_size(width, vpitch) * c;
209 }
210 EXPORT_SYMBOL_GPL(font_data_glyph_buf);
211 
212 /**
213  * font_data_is_equal - Compares font data for equality
214  * @lhs: Left-hand side font data
215  * @rhs: Right-hand-size font data
216  *
217  * Font data is equal if is constain the same sequence of values. The
218  * helper also use the checksum, if both arguments contain it. Font data
219  * coming from different origins, internal or from user space, is never
220  * equal. Allowing this would break reference counting.
221  *
222  * Returns:
223  * True if the given font data is equal, false otherwise.
224  */
225 bool font_data_is_equal(font_data_t *lhs, font_data_t *rhs)
226 {
227 	if (font_data_is_internal(lhs) != font_data_is_internal(rhs))
228 		return false;
229 	if (font_data_size(lhs) != font_data_size(rhs))
230 		return false;
231 	if (FNTSUM(lhs) && FNTSUM(rhs) && FNTSUM(lhs) != FNTSUM(rhs))
232 		return false;
233 
234 	return !memcmp(lhs, rhs, FNTSIZE(lhs));
235 }
236 EXPORT_SYMBOL_GPL(font_data_is_equal);
237 
238 /**
239  * font_data_export - Stores font data for user space
240  * @fd: Font data
241  * @font: A font for user space
242  * @vpitch: The size of a single glyph in @font in bytes
243  *
244  * Store the font data given in @fd to the font in @font. Values and
245  * pointers in @font are pre-initialized. This helper mostly checks some
246  * corner cases and translates glyph sizes according to the value given
247  * @vpitch.
248  *
249  * Returns:
250  * 0 on success, or a negative errno code otherwise.
251  */
252 int font_data_export(font_data_t *fd, struct console_font *font, unsigned int vpitch)
253 {
254 	const unsigned char *font_data = font_data_buf(fd);
255 	unsigned char *data = font->data;
256 	unsigned int pitch = console_font_pitch(font);
257 	unsigned int glyphsize, i;
258 
259 	if (!font->width || !font->height || !font->charcount || !font->data)
260 		return 0;
261 
262 	glyphsize = font->height * pitch;
263 
264 	if (font->charcount * glyphsize > font_data_size(fd))
265 		return -EINVAL;
266 
267 	for (i = 0; i < font->charcount; i++) {
268 		memcpy(data, font_data, glyphsize);
269 		memset(data + glyphsize, 0, pitch * vpitch - glyphsize);
270 		data += pitch * vpitch;
271 		font_data += glyphsize;
272 	}
273 
274 	return 0;
275 }
276 EXPORT_SYMBOL_GPL(font_data_export);
277 
278 /*
279  * Font lookup
280  */
281 
282 static const struct font_desc *fonts[] = {
283 #ifdef CONFIG_FONT_8x8
284 	&font_vga_8x8,
285 #endif
286 #ifdef CONFIG_FONT_8x16
287 	&font_vga_8x16,
288 #endif
289 #ifdef CONFIG_FONT_6x11
290 	&font_vga_6x11,
291 #endif
292 #ifdef CONFIG_FONT_7x14
293 	&font_7x14,
294 #endif
295 #ifdef CONFIG_FONT_SUN8x16
296 	&font_sun_8x16,
297 #endif
298 #ifdef CONFIG_FONT_SUN12x22
299 	&font_sun_12x22,
300 #endif
301 #ifdef CONFIG_FONT_10x18
302 	&font_10x18,
303 #endif
304 #ifdef CONFIG_FONT_ACORN_8x8
305 	&font_acorn_8x8,
306 #endif
307 #ifdef CONFIG_FONT_PEARL_8x8
308 	&font_pearl_8x8,
309 #endif
310 #ifdef CONFIG_FONT_MINI_4x6
311 	&font_mini_4x6,
312 #endif
313 #ifdef CONFIG_FONT_6x10
314 	&font_6x10,
315 #endif
316 #ifdef CONFIG_FONT_TER10x18
317 	&font_ter_10x18,
318 #endif
319 #ifdef CONFIG_FONT_TER16x32
320 	&font_ter_16x32,
321 #endif
322 #ifdef CONFIG_FONT_6x8
323 	&font_6x8,
324 #endif
325 };
326 
327 #define num_fonts ARRAY_SIZE(fonts)
328 
329 #ifdef NO_FONTS
330 #error No fonts configured.
331 #endif
332 
333 
334 /**
335  *	find_font - find a font
336  *	@name: string name of a font
337  *
338  *	Find a specified font with string name @name.
339  *
340  *	Returns %NULL if no font found, or a pointer to the
341  *	specified font.
342  *
343  */
344 const struct font_desc *find_font(const char *name)
345 {
346 	unsigned int i;
347 
348 	BUILD_BUG_ON(!num_fonts);
349 	for (i = 0; i < num_fonts; i++)
350 		if (!strcmp(fonts[i]->name, name))
351 			return fonts[i];
352 	return NULL;
353 }
354 EXPORT_SYMBOL(find_font);
355 
356 
357 /**
358  *	get_default_font - get default font
359  *	@xres: screen size of X
360  *	@yres: screen size of Y
361  *	@font_w: bit array of supported widths (1 - FB_MAX_BLIT_WIDTH)
362  *	@font_h: bit array of supported heights (1 - FB_MAX_BLIT_HEIGHT)
363  *
364  *	Get the default font for a specified screen size.
365  *	Dimensions are in pixels.
366  *
367  *	font_w or font_h being NULL means all values are supported.
368  *
369  *	Returns %NULL if no font is found, or a pointer to the
370  *	chosen font.
371  *
372  */
373 const struct font_desc *get_default_font(int xres, int yres,
374 					 unsigned long *font_w,
375 					 unsigned long *font_h)
376 {
377 	int i, c, cc, res;
378 	const struct font_desc *f, *g;
379 
380 	g = NULL;
381 	cc = -10000;
382 	for (i = 0; i < num_fonts; i++) {
383 		f = fonts[i];
384 		c = f->pref;
385 #if defined(__mc68000__)
386 #ifdef CONFIG_FONT_PEARL_8x8
387 		if (MACH_IS_AMIGA && f->idx == PEARL8x8_IDX)
388 			c = 100;
389 #endif
390 #ifdef CONFIG_FONT_6x11
391 		if (MACH_IS_MAC && xres < 640 && f->idx == VGA6x11_IDX)
392 			c = 100;
393 #endif
394 #endif
395 		if ((yres < 400) == (f->height <= 8))
396 			c += 1000;
397 
398 		/* prefer a bigger font for high resolution */
399 		res = (xres / f->width) * (yres / f->height) / 1000;
400 		if (res > 20)
401 			c += 20 - res;
402 
403 		if ((!font_w || test_bit(f->width - 1, font_w)) &&
404 		    (!font_h || test_bit(f->height - 1, font_h)))
405 			c += 1000;
406 
407 		if (c > cc) {
408 			cc = c;
409 			g = f;
410 		}
411 	}
412 	return g;
413 }
414 EXPORT_SYMBOL(get_default_font);
415 
416 MODULE_AUTHOR("James Simmons <jsimmons@users.sf.net>");
417 MODULE_DESCRIPTION("Console Fonts");
418 MODULE_LICENSE("GPL");
419