vt_font.c revision 331984
1/*- 2 * Copyright (c) 2009 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Ed Schouten under sponsorship from the 6 * FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/cdefs.h> 31__FBSDID("$FreeBSD: releng/10.3/sys/dev/vt/vt_font.c 331984 2018-04-04 05:33:56Z gordon $"); 32 33#include <sys/param.h> 34#include <sys/kernel.h> 35#include <sys/malloc.h> 36#include <sys/refcount.h> 37#include <sys/systm.h> 38 39#include <dev/vt/vt.h> 40 41static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font"); 42 43/* Some limits to prevent abnormal fonts from being loaded. */ 44#define VTFONT_MAXMAPPINGS 65536 45#define VTFONT_MAXGLYPHS 131072 46#define VTFONT_MAXGLYPHSIZE 2097152 47#define VTFONT_MAXDIMENSION 128 48 49static uint16_t 50vtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) 51{ 52 int min, mid, max; 53 54 min = 0; 55 max = len - 1; 56 57 /* Empty font map. */ 58 if (len == 0) 59 return (0); 60 /* Character below minimal entry. */ 61 if (src < map[0].vfm_src) 62 return (0); 63 /* Optimization: ASCII characters occur very often. */ 64 if (src <= map[0].vfm_src + map[0].vfm_len) 65 return (src - map[0].vfm_src + map[0].vfm_dst); 66 /* Character above maximum entry. */ 67 if (src > map[max].vfm_src + map[max].vfm_len) 68 return (0); 69 70 /* Binary search. */ 71 while (max >= min) { 72 mid = (min + max) / 2; 73 if (src < map[mid].vfm_src) 74 max = mid - 1; 75 else if (src > map[mid].vfm_src + map[mid].vfm_len) 76 min = mid + 1; 77 else 78 return (src - map[mid].vfm_src + map[mid].vfm_dst); 79 } 80 81 return (0); 82} 83 84const uint8_t * 85vtfont_lookup(const struct vt_font *vf, term_char_t c) 86{ 87 uint32_t src; 88 uint16_t dst; 89 size_t stride; 90 unsigned int normal_map; 91 unsigned int bold_map; 92 93 /* 94 * No support for printing right hand sides for CJK fullwidth 95 * characters. Simply print a space and assume that the left 96 * hand side describes the entire character. 97 */ 98 src = TCHAR_CHARACTER(c); 99 if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) { 100 normal_map = VFNT_MAP_NORMAL_RIGHT; 101 bold_map = VFNT_MAP_BOLD_RIGHT; 102 } else { 103 normal_map = VFNT_MAP_NORMAL; 104 bold_map = VFNT_MAP_BOLD; 105 } 106 107 if (TCHAR_FORMAT(c) & TF_BOLD) { 108 dst = vtfont_bisearch(vf->vf_map[bold_map], 109 vf->vf_map_count[bold_map], src); 110 if (dst != 0) 111 goto found; 112 } 113 dst = vtfont_bisearch(vf->vf_map[normal_map], 114 vf->vf_map_count[normal_map], src); 115 116found: 117 stride = howmany(vf->vf_width, 8) * vf->vf_height; 118 return (&vf->vf_bytes[dst * stride]); 119} 120 121struct vt_font * 122vtfont_ref(struct vt_font *vf) 123{ 124 125 refcount_acquire(&vf->vf_refcount); 126 return (vf); 127} 128 129void 130vtfont_unref(struct vt_font *vf) 131{ 132 unsigned int i; 133 134 if (refcount_release(&vf->vf_refcount)) { 135 for (i = 0; i < VFNT_MAPS; i++) 136 free(vf->vf_map[i], M_VTFONT); 137 free(vf->vf_bytes, M_VTFONT); 138 free(vf, M_VTFONT); 139 } 140} 141 142static int 143vtfont_validate_map(struct vt_font_map *vfm, unsigned int length, 144 unsigned int glyph_count) 145{ 146 unsigned int i, last = 0; 147 148 for (i = 0; i < length; i++) { 149 /* Not ordered. */ 150 if (i > 0 && vfm[i].vfm_src <= last) 151 return (EINVAL); 152 /* 153 * Destination extends amount of glyphs. 154 */ 155 if (vfm[i].vfm_dst >= glyph_count || 156 vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count) 157 return (EINVAL); 158 last = vfm[i].vfm_src + vfm[i].vfm_len; 159 } 160 161 return (0); 162} 163 164int 165vtfont_load(vfnt_t *f, struct vt_font **ret) 166{ 167 size_t glyphsize, mapsize; 168 struct vt_font *vf; 169 int error; 170 unsigned int i; 171 172 /* Make sure the dimensions are valid. */ 173 if (f->width < 1 || f->height < 1) 174 return (EINVAL); 175 if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION || 176 f->glyph_count > VTFONT_MAXGLYPHS) 177 return (E2BIG); 178 179 /* Not too many mappings. */ 180 for (i = 0; i < VFNT_MAPS; i++) 181 if (f->map_count[i] > VTFONT_MAXMAPPINGS) 182 return (E2BIG); 183 184 /* Character 0 must always be present. */ 185 if (f->glyph_count < 1) 186 return (EINVAL); 187 188 glyphsize = howmany(f->width, 8) * f->height * f->glyph_count; 189 if (glyphsize > VTFONT_MAXGLYPHSIZE) 190 return (E2BIG); 191 192 /* Allocate new font structure. */ 193 vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO); 194 vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK); 195 vf->vf_height = f->height; 196 vf->vf_width = f->width; 197 vf->vf_refcount = 1; 198 199 /* Allocate, copy in, and validate mappings. */ 200 for (i = 0; i < VFNT_MAPS; i++) { 201 vf->vf_map_count[i] = f->map_count[i]; 202 if (f->map_count[i] == 0) 203 continue; 204 mapsize = f->map_count[i] * sizeof(struct vt_font_map); 205 vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); 206 error = copyin(f->map[i], vf->vf_map[i], mapsize); 207 if (error) 208 goto bad; 209 error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i], 210 f->glyph_count); 211 if (error) 212 goto bad; 213 } 214 215 /* Copy in glyph data. */ 216 error = copyin(f->glyphs, vf->vf_bytes, glyphsize); 217 if (error) 218 goto bad; 219 220 /* Success. */ 221 *ret = vf; 222 return (0); 223 224bad: vtfont_unref(vf); 225 return (error); 226} 227