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