// SPDX-License-Identifier: GPL-2.0-only /* * Font rotation * * Copyright (C) 2005 Antonino Daplas * * This file is subject to the terms and conditions of the GNU General Public * License. See the file COPYING in the main directory of this archive for * more details. */ #include #include #include #include #include #include #include "font.h" /* number of bits per line */ static unsigned int font_glyph_bit_pitch(unsigned int width) { return round_up(width, 8); } static unsigned int __font_glyph_pos(unsigned int x, unsigned int y, unsigned int bit_pitch, unsigned int *bit) { unsigned int off = y * bit_pitch + x; unsigned int bit_shift = off % 8; *bit = 0x80 >> bit_shift; /* MSB has position 0, LSB has position 7 */ return off / 8; } static bool font_glyph_test_bit(const unsigned char *glyph, unsigned int x, unsigned int y, unsigned int bit_pitch) { unsigned int bit; unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit); return glyph[i] & bit; } static void font_glyph_set_bit(unsigned char *glyph, unsigned int x, unsigned int y, unsigned int bit_pitch) { unsigned int bit; unsigned int i = __font_glyph_pos(x, y, bit_pitch, &bit); glyph[i] |= bit; } static void __font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height, unsigned char *out) { unsigned int x, y; unsigned int shift = (8 - (height % 8)) & 7; unsigned int bit_pitch = font_glyph_bit_pitch(width); unsigned int out_bit_pitch = font_glyph_bit_pitch(height); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (font_glyph_test_bit(glyph, x, y, bit_pitch)) { font_glyph_set_bit(out, out_bit_pitch - 1 - y - shift, x, out_bit_pitch); } } } } /** * font_glyph_rotate_90 - Rotate a glyph pattern by 90° in clockwise direction * @glyph: The glyph to rotate * @width: The glyph width in bits per scanline * @height: The number of scanlines in the glyph * @out: The rotated glyph bitmap * * The parameters @width and @height refer to the input glyph given in @glyph. * The caller has to provide the output buffer @out of sufficient size to hold * the rotated glyph. Rotating by 90° flips the width and height for the output * glyph. Depending on the glyph pitch, the size of the output glyph can be * different than the size of the input. Callers have to take this into account * when allocating the output memory. */ void font_glyph_rotate_90(const unsigned char *glyph, unsigned int width, unsigned int height, unsigned char *out) { memset(out, 0, font_glyph_size(height, width)); /* flip width/height */ __font_glyph_rotate_90(glyph, width, height, out); } EXPORT_SYMBOL_GPL(font_glyph_rotate_90); static void __font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height, unsigned char *out) { unsigned int x, y; unsigned int shift = (8 - (width % 8)) & 7; unsigned int bit_pitch = font_glyph_bit_pitch(width); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (font_glyph_test_bit(glyph, x, y, bit_pitch)) { font_glyph_set_bit(out, width - (1 + x + shift), height - (1 + y), bit_pitch); } } } } /** * font_glyph_rotate_180 - Rotate a glyph pattern by 180° * @glyph: The glyph to rotate * @width: The glyph width in bits per scanline * @height: The number of scanlines in the glyph * @out: The rotated glyph bitmap * * The parameters @width and @height refer to the input glyph given in @glyph. * The caller has to provide the output buffer @out of sufficient size to hold * the rotated glyph. */ void font_glyph_rotate_180(const unsigned char *glyph, unsigned int width, unsigned int height, unsigned char *out) { memset(out, 0, font_glyph_size(width, height)); __font_glyph_rotate_180(glyph, width, height, out); } EXPORT_SYMBOL_GPL(font_glyph_rotate_180); static void __font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height, unsigned char *out) { unsigned int x, y; unsigned int shift = (8 - (width % 8)) & 7; unsigned int bit_pitch = font_glyph_bit_pitch(width); unsigned int out_bit_pitch = font_glyph_bit_pitch(height); for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (font_glyph_test_bit(glyph, x, y, bit_pitch)) font_glyph_set_bit(out, y, bit_pitch - 1 - x - shift, out_bit_pitch); } } } /** * font_glyph_rotate_270 - Rotate a glyph pattern by 270° in clockwise direction * @glyph: The glyph to rotate * @width: The glyph width in bits per scanline * @height: The number of scanlines in the glyph * @out: The rotated glyph bitmap * * The parameters @width and @height refer to the input glyph given in @glyph. * The caller has to provide the output buffer @out of sufficient size to hold * the rotated glyph. Rotating by 270° flips the width and height for the output * glyph. Depending on the glyph pitch, the size of the output glyph can be * different than the size of the input. Callers have to take this into account * when allocating the output memory. */ void font_glyph_rotate_270(const unsigned char *glyph, unsigned int width, unsigned int height, unsigned char *out) { memset(out, 0, font_glyph_size(height, width)); /* flip width/height */ __font_glyph_rotate_270(glyph, width, height, out); } EXPORT_SYMBOL_GPL(font_glyph_rotate_270); /** * font_data_rotate - Rotate font data by multiples of 90° * @fd: The font data to rotate * @width: The glyph width in bits per scanline * @height: The number of scanlines in the glyph * @charcount: The number of glyphs in the font * @steps: Number of rotation steps of 90° * @buf: Preallocated output buffer; can be NULL * @bufsize: The size of @buf in bytes; can be NULL * * The parameters @width and @height refer to the visible number of pixels * and scanlines in a single glyph. The number of glyphs is given in @charcount. * Rotation happens in steps of 90°. The @steps parameter can have any value, * but only 0 to 3 produce distinct results. With 4 or higher, a full rotation * has been performed. You can pass any value for @steps and the helper will * perform the appropriate rotation. Note that the returned buffer is not * compatible with font_data_t. It only contains glyph data in the same format * as returned by font_data_buf(). Callers are responsible to free the returned * buffer with kfree(). Font rotation typically happens when displays get * re-oriented. To avoid unnecessary re-allocation of the memory buffer, the * caller can pass in an earlier result buffer in @buf for reuse. The old and * new buffer sizes are given and retrieved by the caller in @bufsize. The * allocation semantics are compatible with krealloc(). * * Returns: * A buffer with rotated glyphs on success, or an error pointer otherwise */ unsigned char *font_data_rotate(font_data_t *fd, unsigned int width, unsigned int height, unsigned int charcount, unsigned int steps, unsigned char *buf, size_t *bufsize) { const unsigned char *src = font_data_buf(fd); unsigned int s_cellsize = font_glyph_size(width, height); unsigned int d_cellsize, i; unsigned char *dst; size_t size; steps %= 4; switch (steps) { case 0: case 2: d_cellsize = s_cellsize; break; case 1: case 3: d_cellsize = font_glyph_size(height, width); /* flip width/height */ break; } if (check_mul_overflow(charcount, d_cellsize, &size)) return ERR_PTR(-EINVAL); if (!buf || !bufsize || size > *bufsize) { dst = kmalloc_array(charcount, d_cellsize, GFP_KERNEL); if (!dst) return ERR_PTR(-ENOMEM); kfree(buf); buf = dst; if (bufsize) *bufsize = size; } else { dst = buf; } switch (steps) { case 0: memcpy(dst, src, size); break; case 1: memset(dst, 0, size); for (i = 0; i < charcount; ++i) { __font_glyph_rotate_90(src, width, height, dst); src += s_cellsize; dst += d_cellsize; } break; case 2: memset(dst, 0, size); for (i = 0; i < charcount; ++i) { __font_glyph_rotate_180(src, width, height, dst); src += s_cellsize; dst += d_cellsize; } break; case 3: memset(dst, 0, size); for (i = 0; i < charcount; ++i) { __font_glyph_rotate_270(src, width, height, dst); src += s_cellsize; dst += d_cellsize; } break; } return buf; } EXPORT_SYMBOL_GPL(font_data_rotate);