xref: /linux/lib/fonts/font_rotate.c (revision 13ad98eaabef611f042d49a9077be060ad03284d)
1bdfd9432SThomas Zimmermann // SPDX-License-Identifier: GPL-2.0-only
2bdfd9432SThomas Zimmermann /*
3bdfd9432SThomas Zimmermann  * Font rotation
4bdfd9432SThomas Zimmermann  *
5bdfd9432SThomas Zimmermann  *    Copyright (C) 2005 Antonino Daplas <adaplas @pol.net>
6bdfd9432SThomas Zimmermann  *
7bdfd9432SThomas Zimmermann  * This file is subject to the terms and conditions of the GNU General Public
8bdfd9432SThomas Zimmermann  * License.  See the file COPYING in the main directory of this archive for
9bdfd9432SThomas Zimmermann  * more details.
10bdfd9432SThomas Zimmermann  */
11bdfd9432SThomas Zimmermann 
12cfa72955SThomas Zimmermann #include <linux/errno.h>
13bdfd9432SThomas Zimmermann #include <linux/export.h>
14bdfd9432SThomas Zimmermann #include <linux/math.h>
15cfa72955SThomas Zimmermann #include <linux/overflow.h>
16cfa72955SThomas Zimmermann #include <linux/slab.h>
17bdfd9432SThomas Zimmermann #include <linux/string.h>
18bdfd9432SThomas Zimmermann 
19bdfd9432SThomas Zimmermann #include "font.h"
20bdfd9432SThomas Zimmermann 
21a30e9e6bSThomas Zimmermann /* number of bits per line */
22a30e9e6bSThomas Zimmermann static unsigned int font_glyph_bit_pitch(unsigned int width)
23a30e9e6bSThomas Zimmermann {
24a30e9e6bSThomas Zimmermann 	return round_up(width, 8);
25a30e9e6bSThomas Zimmermann }
26a30e9e6bSThomas Zimmermann 
276ad4ed84SThomas Zimmermann static unsigned int __font_glyph_pos(unsigned int x, unsigned int y, unsigned int bit_pitch,
286ad4ed84SThomas Zimmermann 				     unsigned int *bit)
29bdfd9432SThomas Zimmermann {
306ad4ed84SThomas Zimmermann 	unsigned int off = y * bit_pitch + x;
316ad4ed84SThomas Zimmermann 	unsigned int bit_shift = off % 8;
32bdfd9432SThomas Zimmermann 
336ad4ed84SThomas Zimmermann 	*bit = 0x80 >> bit_shift; /* MSB has position 0, LSB has position 7 */
346ad4ed84SThomas Zimmermann 
356ad4ed84SThomas Zimmermann 	return off / 8;
36bdfd9432SThomas Zimmermann }
37bdfd9432SThomas Zimmermann 
386ad4ed84SThomas Zimmermann static bool font_glyph_test_bit(const unsigned char *glyph, unsigned int x, unsigned int y,
396ad4ed84SThomas Zimmermann 				unsigned int bit_pitch)
40bdfd9432SThomas Zimmermann {
416ad4ed84SThomas Zimmermann 	unsigned int bit;
426ad4ed84SThomas Zimmermann 	unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit);
43bdfd9432SThomas Zimmermann 
446ad4ed84SThomas Zimmermann 	return glyph[i] & bit;
456ad4ed84SThomas Zimmermann }
46bdfd9432SThomas Zimmermann 
476ad4ed84SThomas Zimmermann static void font_glyph_set_bit(unsigned char *glyph, unsigned int x, unsigned int y,
486ad4ed84SThomas Zimmermann 			       unsigned int bit_pitch)
496ad4ed84SThomas Zimmermann {
506ad4ed84SThomas Zimmermann 	unsigned int bit;
516ad4ed84SThomas Zimmermann 	unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit);
526ad4ed84SThomas Zimmermann 
536ad4ed84SThomas Zimmermann 	glyph[i] |= bit;
54bdfd9432SThomas Zimmermann }
55bdfd9432SThomas Zimmermann 
56a30e9e6bSThomas Zimmermann static void __font_glyph_rotate_90(const unsigned char *glyph,
57a30e9e6bSThomas Zimmermann 				   unsigned int width, unsigned int height,
58a30e9e6bSThomas Zimmermann 				   unsigned char *out)
59bdfd9432SThomas Zimmermann {
60a30e9e6bSThomas Zimmermann 	unsigned int x, y;
61a30e9e6bSThomas Zimmermann 	unsigned int shift = (8 - (height % 8)) & 7;
62a30e9e6bSThomas Zimmermann 	unsigned int bit_pitch = font_glyph_bit_pitch(width);
63a30e9e6bSThomas Zimmermann 	unsigned int out_bit_pitch = font_glyph_bit_pitch(height);
64bdfd9432SThomas Zimmermann 
65a30e9e6bSThomas Zimmermann 	for (y = 0; y < height; y++) {
66a30e9e6bSThomas Zimmermann 		for (x = 0; x < width; x++) {
67a30e9e6bSThomas Zimmermann 			if (font_glyph_test_bit(glyph, x, y, bit_pitch)) {
68a30e9e6bSThomas Zimmermann 				font_glyph_set_bit(out, out_bit_pitch - 1 - y - shift, x,
69a30e9e6bSThomas Zimmermann 						   out_bit_pitch);
70a30e9e6bSThomas Zimmermann 			}
71bdfd9432SThomas Zimmermann 		}
72bdfd9432SThomas Zimmermann 	}
73bdfd9432SThomas Zimmermann }
74bdfd9432SThomas Zimmermann 
75bdfd9432SThomas Zimmermann /**
76bdfd9432SThomas Zimmermann  * font_glyph_rotate_90 - Rotate a glyph pattern by 90° in clockwise direction
77bdfd9432SThomas Zimmermann  * @glyph: The glyph to rotate
78bdfd9432SThomas Zimmermann  * @width: The glyph width in bits per scanline
79bdfd9432SThomas Zimmermann  * @height: The number of scanlines in the glyph
80bdfd9432SThomas Zimmermann  * @out: The rotated glyph bitmap
81bdfd9432SThomas Zimmermann  *
82bdfd9432SThomas Zimmermann  * The parameters @width and @height refer to the input glyph given in @glyph.
83bdfd9432SThomas Zimmermann  * The caller has to provide the output buffer @out of sufficient size to hold
84bdfd9432SThomas Zimmermann  * the rotated glyph. Rotating by 90° flips the width and height for the output
85bdfd9432SThomas Zimmermann  * glyph. Depending on the glyph pitch, the size of the output glyph can be
86bdfd9432SThomas Zimmermann  * different than the size of the input. Callers have to take this into account
87bdfd9432SThomas Zimmermann  * when allocating the output memory.
88bdfd9432SThomas Zimmermann  */
89bdfd9432SThomas Zimmermann void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height,
90bdfd9432SThomas Zimmermann 			  unsigned char *out)
91bdfd9432SThomas Zimmermann {
92bdfd9432SThomas Zimmermann 	memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
93bdfd9432SThomas Zimmermann 
94a30e9e6bSThomas Zimmermann 	__font_glyph_rotate_90(glyph, width, height, out);
95bdfd9432SThomas Zimmermann }
96bdfd9432SThomas Zimmermann EXPORT_SYMBOL_GPL(font_glyph_rotate_90);
97bdfd9432SThomas Zimmermann 
98a30e9e6bSThomas Zimmermann static void __font_glyph_rotate_180(const unsigned char *glyph,
99a30e9e6bSThomas Zimmermann 				    unsigned int width, unsigned int height,
100a30e9e6bSThomas Zimmermann 				    unsigned char *out)
101bdfd9432SThomas Zimmermann {
102a30e9e6bSThomas Zimmermann 	unsigned int x, y;
103a30e9e6bSThomas Zimmermann 	unsigned int shift = (8 - (width % 8)) & 7;
104a30e9e6bSThomas Zimmermann 	unsigned int bit_pitch = font_glyph_bit_pitch(width);
105bdfd9432SThomas Zimmermann 
106a30e9e6bSThomas Zimmermann 	for (y = 0; y < height; y++) {
107a30e9e6bSThomas Zimmermann 		for (x = 0; x < width; x++) {
108a30e9e6bSThomas Zimmermann 			if (font_glyph_test_bit(glyph, x, y, bit_pitch)) {
109*d237f719SThomas Zimmermann 				font_glyph_set_bit(out, bit_pitch - 1 - x - shift, height - 1 - y,
110a30e9e6bSThomas Zimmermann 						   bit_pitch);
111a30e9e6bSThomas Zimmermann 			}
112bdfd9432SThomas Zimmermann 		}
113bdfd9432SThomas Zimmermann 	}
114bdfd9432SThomas Zimmermann }
115bdfd9432SThomas Zimmermann 
116bdfd9432SThomas Zimmermann /**
117bdfd9432SThomas Zimmermann  * font_glyph_rotate_180 - Rotate a glyph pattern by 180°
118bdfd9432SThomas Zimmermann  * @glyph: The glyph to rotate
119bdfd9432SThomas Zimmermann  * @width: The glyph width in bits per scanline
120bdfd9432SThomas Zimmermann  * @height: The number of scanlines in the glyph
121bdfd9432SThomas Zimmermann  * @out: The rotated glyph bitmap
122bdfd9432SThomas Zimmermann  *
123bdfd9432SThomas Zimmermann  * The parameters @width and @height refer to the input glyph given in @glyph.
124bdfd9432SThomas Zimmermann  * The caller has to provide the output buffer @out of sufficient size to hold
125bdfd9432SThomas Zimmermann  * the rotated glyph.
126bdfd9432SThomas Zimmermann  */
127bdfd9432SThomas Zimmermann void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height,
128bdfd9432SThomas Zimmermann 			   unsigned char *out)
129bdfd9432SThomas Zimmermann {
130bdfd9432SThomas Zimmermann 	memset(out, 0, font_glyph_size(width, height));
131bdfd9432SThomas Zimmermann 
132a30e9e6bSThomas Zimmermann 	__font_glyph_rotate_180(glyph, width, height, out);
133bdfd9432SThomas Zimmermann }
134bdfd9432SThomas Zimmermann EXPORT_SYMBOL_GPL(font_glyph_rotate_180);
135bdfd9432SThomas Zimmermann 
136a30e9e6bSThomas Zimmermann static void __font_glyph_rotate_270(const unsigned char *glyph,
137a30e9e6bSThomas Zimmermann 				    unsigned int width, unsigned int height,
138a30e9e6bSThomas Zimmermann 				    unsigned char *out)
139bdfd9432SThomas Zimmermann {
140a30e9e6bSThomas Zimmermann 	unsigned int x, y;
141a30e9e6bSThomas Zimmermann 	unsigned int shift = (8 - (width % 8)) & 7;
142a30e9e6bSThomas Zimmermann 	unsigned int bit_pitch = font_glyph_bit_pitch(width);
143a30e9e6bSThomas Zimmermann 	unsigned int out_bit_pitch = font_glyph_bit_pitch(height);
144bdfd9432SThomas Zimmermann 
145a30e9e6bSThomas Zimmermann 	for (y = 0; y < height; y++) {
146a30e9e6bSThomas Zimmermann 		for (x = 0; x < width; x++) {
147a30e9e6bSThomas Zimmermann 			if (font_glyph_test_bit(glyph, x, y, bit_pitch))
148a30e9e6bSThomas Zimmermann 				font_glyph_set_bit(out, y, bit_pitch - 1 - x - shift,
149a30e9e6bSThomas Zimmermann 						   out_bit_pitch);
150bdfd9432SThomas Zimmermann 		}
151bdfd9432SThomas Zimmermann 	}
152bdfd9432SThomas Zimmermann }
153bdfd9432SThomas Zimmermann 
154bdfd9432SThomas Zimmermann /**
155bdfd9432SThomas Zimmermann  * font_glyph_rotate_270 - Rotate a glyph pattern by 270° in clockwise direction
156bdfd9432SThomas Zimmermann  * @glyph: The glyph to rotate
157bdfd9432SThomas Zimmermann  * @width: The glyph width in bits per scanline
158bdfd9432SThomas Zimmermann  * @height: The number of scanlines in the glyph
159bdfd9432SThomas Zimmermann  * @out: The rotated glyph bitmap
160bdfd9432SThomas Zimmermann  *
161bdfd9432SThomas Zimmermann  * The parameters @width and @height refer to the input glyph given in @glyph.
162bdfd9432SThomas Zimmermann  * The caller has to provide the output buffer @out of sufficient size to hold
163bdfd9432SThomas Zimmermann  * the rotated glyph. Rotating by 270° flips the width and height for the output
164bdfd9432SThomas Zimmermann  * glyph. Depending on the glyph pitch, the size of the output glyph can be
165bdfd9432SThomas Zimmermann  * different than the size of the input. Callers have to take this into account
166bdfd9432SThomas Zimmermann  * when allocating the output memory.
167bdfd9432SThomas Zimmermann  */
168bdfd9432SThomas Zimmermann void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height,
169bdfd9432SThomas Zimmermann 			   unsigned char *out)
170bdfd9432SThomas Zimmermann {
171bdfd9432SThomas Zimmermann 	memset(out, 0, font_glyph_size(height, width)); /* flip width/height */
172bdfd9432SThomas Zimmermann 
173a30e9e6bSThomas Zimmermann 	__font_glyph_rotate_270(glyph, width, height, out);
174bdfd9432SThomas Zimmermann }
175bdfd9432SThomas Zimmermann EXPORT_SYMBOL_GPL(font_glyph_rotate_270);
176cfa72955SThomas Zimmermann 
177cfa72955SThomas Zimmermann /**
178cfa72955SThomas Zimmermann  * font_data_rotate - Rotate font data by multiples of 90°
179cfa72955SThomas Zimmermann  * @fd: The font data to rotate
180cfa72955SThomas Zimmermann  * @width: The glyph width in bits per scanline
181cfa72955SThomas Zimmermann  * @height: The number of scanlines in the glyph
182cfa72955SThomas Zimmermann  * @charcount: The number of glyphs in the font
183cfa72955SThomas Zimmermann  * @steps: Number of rotation steps of 90°
184cfa72955SThomas Zimmermann  * @buf: Preallocated output buffer; can be NULL
185cfa72955SThomas Zimmermann  * @bufsize: The size of @buf in bytes; can be NULL
186cfa72955SThomas Zimmermann  *
187cfa72955SThomas Zimmermann  * The parameters @width and @height refer to the visible number of pixels
188cfa72955SThomas Zimmermann  * and scanlines in a single glyph. The number of glyphs is given in @charcount.
189cfa72955SThomas Zimmermann  * Rotation happens in steps of 90°. The @steps parameter can have any value,
190cfa72955SThomas Zimmermann  * but only 0 to 3 produce distinct results. With 4 or higher, a full rotation
191cfa72955SThomas Zimmermann  * has been performed. You can pass any value for @steps and the helper will
192cfa72955SThomas Zimmermann  * perform the appropriate rotation. Note that the returned buffer is not
193cfa72955SThomas Zimmermann  * compatible with font_data_t. It only contains glyph data in the same format
194cfa72955SThomas Zimmermann  * as returned by font_data_buf(). Callers are responsible to free the returned
195cfa72955SThomas Zimmermann  * buffer with kfree(). Font rotation typically happens when displays get
196cfa72955SThomas Zimmermann  * re-oriented. To avoid unnecessary re-allocation of the memory buffer, the
197cfa72955SThomas Zimmermann  * caller can pass in an earlier result buffer in @buf for reuse. The old and
198cfa72955SThomas Zimmermann  * new buffer sizes are given and retrieved by the caller in @bufsize. The
199cfa72955SThomas Zimmermann  * allocation semantics are compatible with krealloc().
200cfa72955SThomas Zimmermann  *
201cfa72955SThomas Zimmermann  * Returns:
202cfa72955SThomas Zimmermann  * A buffer with rotated glyphs on success, or an error pointer otherwise
203cfa72955SThomas Zimmermann  */
204cfa72955SThomas Zimmermann unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height,
205cfa72955SThomas Zimmermann 				unsigned int charcount, unsigned int steps,
206cfa72955SThomas Zimmermann 				unsigned char *buf, size_t *bufsize)
207cfa72955SThomas Zimmermann {
208cfa72955SThomas Zimmermann 	const unsigned char *src = font_data_buf(fd);
209cfa72955SThomas Zimmermann 	unsigned int s_cellsize = font_glyph_size(width, height);
210cfa72955SThomas Zimmermann 	unsigned int d_cellsize, i;
211cfa72955SThomas Zimmermann 	unsigned char *dst;
212cfa72955SThomas Zimmermann 	size_t size;
213cfa72955SThomas Zimmermann 
214cfa72955SThomas Zimmermann 	steps %= 4;
215cfa72955SThomas Zimmermann 
216cfa72955SThomas Zimmermann 	switch (steps) {
217cfa72955SThomas Zimmermann 	case 0:
218cfa72955SThomas Zimmermann 	case 2:
219cfa72955SThomas Zimmermann 		d_cellsize = s_cellsize;
220cfa72955SThomas Zimmermann 		break;
221cfa72955SThomas Zimmermann 	case 1:
222cfa72955SThomas Zimmermann 	case 3:
223cfa72955SThomas Zimmermann 		d_cellsize = font_glyph_size(height, width); /* flip width/height */
224cfa72955SThomas Zimmermann 		break;
225cfa72955SThomas Zimmermann 	}
226cfa72955SThomas Zimmermann 
227cfa72955SThomas Zimmermann 	if (check_mul_overflow(charcount, d_cellsize, &size))
228cfa72955SThomas Zimmermann 		return ERR_PTR(-EINVAL);
229cfa72955SThomas Zimmermann 
230cfa72955SThomas Zimmermann 	if (!buf || !bufsize || size > *bufsize) {
231cfa72955SThomas Zimmermann 		dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL);
232cfa72955SThomas Zimmermann 		if (!dst)
233cfa72955SThomas Zimmermann 			return ERR_PTR(-ENOMEM);
234cfa72955SThomas Zimmermann 
235cfa72955SThomas Zimmermann 		kfree(buf);
236cfa72955SThomas Zimmermann 		buf = dst;
237cfa72955SThomas Zimmermann 		if (bufsize)
238cfa72955SThomas Zimmermann 			*bufsize = size;
239cfa72955SThomas Zimmermann 	} else {
240cfa72955SThomas Zimmermann 		dst = buf;
241cfa72955SThomas Zimmermann 	}
242cfa72955SThomas Zimmermann 
243cfa72955SThomas Zimmermann 	switch (steps) {
244cfa72955SThomas Zimmermann 	case 0:
245cfa72955SThomas Zimmermann 		memcpy(dst, src, size);
246cfa72955SThomas Zimmermann 		break;
247cfa72955SThomas Zimmermann 	case 1:
248cfa72955SThomas Zimmermann 		memset(dst, 0, size);
249cfa72955SThomas Zimmermann 		for (i = 0; i < charcount; ++i) {
250cfa72955SThomas Zimmermann 			__font_glyph_rotate_90(src, width, height, dst);
251cfa72955SThomas Zimmermann 			src += s_cellsize;
252cfa72955SThomas Zimmermann 			dst += d_cellsize;
253cfa72955SThomas Zimmermann 		}
254cfa72955SThomas Zimmermann 		break;
255cfa72955SThomas Zimmermann 	case 2:
256cfa72955SThomas Zimmermann 		memset(dst, 0, size);
257cfa72955SThomas Zimmermann 		for (i = 0; i < charcount; ++i) {
258cfa72955SThomas Zimmermann 			__font_glyph_rotate_180(src, width, height, dst);
259cfa72955SThomas Zimmermann 			src += s_cellsize;
260cfa72955SThomas Zimmermann 			dst += d_cellsize;
261cfa72955SThomas Zimmermann 		}
262cfa72955SThomas Zimmermann 		break;
263cfa72955SThomas Zimmermann 	case 3:
264cfa72955SThomas Zimmermann 		memset(dst, 0, size);
265cfa72955SThomas Zimmermann 		for (i = 0; i < charcount; ++i) {
266cfa72955SThomas Zimmermann 			__font_glyph_rotate_270(src, width, height, dst);
267cfa72955SThomas Zimmermann 			src += s_cellsize;
268cfa72955SThomas Zimmermann 			dst += d_cellsize;
269cfa72955SThomas Zimmermann 		}
270cfa72955SThomas Zimmermann 		break;
271cfa72955SThomas Zimmermann 	}
272cfa72955SThomas Zimmermann 
273cfa72955SThomas Zimmermann 	return buf;
274cfa72955SThomas Zimmermann }
275cfa72955SThomas Zimmermann EXPORT_SYMBOL_GPL(font_data_rotate);
276