1219888Sed/*- 2219888Sed * Copyright (c) 2009 The FreeBSD Foundation 3219888Sed * All rights reserved. 4219888Sed * 5219888Sed * This software was developed by Ed Schouten under sponsorship from the 6219888Sed * FreeBSD Foundation. 7219888Sed * 8219888Sed * Redistribution and use in source and binary forms, with or without 9219888Sed * modification, are permitted provided that the following conditions 10219888Sed * are met: 11219888Sed * 1. Redistributions of source code must retain the above copyright 12219888Sed * notice, this list of conditions and the following disclaimer. 13219888Sed * 2. Redistributions in binary form must reproduce the above copyright 14219888Sed * notice, this list of conditions and the following disclaimer in the 15219888Sed * documentation and/or other materials provided with the distribution. 16219888Sed * 17219888Sed * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18219888Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19219888Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20219888Sed * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21219888Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22219888Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23219888Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24219888Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25219888Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26219888Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27219888Sed * SUCH DAMAGE. 28219888Sed */ 29219888Sed 30219888Sed#include <sys/cdefs.h> 31219888Sed__FBSDID("$FreeBSD: stable/10/sys/dev/vt/vt_font.c 331983 2018-04-04 05:26:33Z gordon $"); 32219888Sed 33219888Sed#include <sys/param.h> 34219888Sed#include <sys/kernel.h> 35219888Sed#include <sys/malloc.h> 36219888Sed#include <sys/refcount.h> 37219888Sed#include <sys/systm.h> 38219888Sed 39219888Sed#include <dev/vt/vt.h> 40219888Sed 41219888Sedstatic MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font"); 42219888Sed 43219888Sed/* Some limits to prevent abnormal fonts from being loaded. */ 44281933Semaste#define VTFONT_MAXMAPPINGS 65536 45331983Sgordon#define VTFONT_MAXGLYPHS 131072 46281933Semaste#define VTFONT_MAXGLYPHSIZE 2097152 47219888Sed#define VTFONT_MAXDIMENSION 128 48219888Sed 49219888Sedstatic uint16_t 50219888Sedvtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) 51219888Sed{ 52219888Sed int min, mid, max; 53219888Sed 54219888Sed min = 0; 55219888Sed max = len - 1; 56219888Sed 57219888Sed /* Empty font map. */ 58219888Sed if (len == 0) 59219888Sed return (0); 60219888Sed /* Character below minimal entry. */ 61219888Sed if (src < map[0].vfm_src) 62219888Sed return (0); 63219888Sed /* Optimization: ASCII characters occur very often. */ 64219888Sed if (src <= map[0].vfm_src + map[0].vfm_len) 65219888Sed return (src - map[0].vfm_src + map[0].vfm_dst); 66219888Sed /* Character above maximum entry. */ 67219888Sed if (src > map[max].vfm_src + map[max].vfm_len) 68219888Sed return (0); 69219888Sed 70219888Sed /* Binary search. */ 71219888Sed while (max >= min) { 72219888Sed mid = (min + max) / 2; 73219888Sed if (src < map[mid].vfm_src) 74219888Sed max = mid - 1; 75219888Sed else if (src > map[mid].vfm_src + map[mid].vfm_len) 76219888Sed min = mid + 1; 77219888Sed else 78219888Sed return (src - map[mid].vfm_src + map[mid].vfm_dst); 79219888Sed } 80219888Sed 81219888Sed return (0); 82219888Sed} 83219888Sed 84219888Sedconst uint8_t * 85219888Sedvtfont_lookup(const struct vt_font *vf, term_char_t c) 86219888Sed{ 87219888Sed uint32_t src; 88219888Sed uint16_t dst; 89219888Sed size_t stride; 90262861Sjhb unsigned int normal_map; 91262861Sjhb unsigned int bold_map; 92219888Sed 93262861Sjhb /* 94262861Sjhb * No support for printing right hand sides for CJK fullwidth 95262861Sjhb * characters. Simply print a space and assume that the left 96262861Sjhb * hand side describes the entire character. 97262861Sjhb */ 98219888Sed src = TCHAR_CHARACTER(c); 99262861Sjhb if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) { 100262861Sjhb normal_map = VFNT_MAP_NORMAL_RIGHT; 101262861Sjhb bold_map = VFNT_MAP_BOLD_RIGHT; 102262861Sjhb } else { 103262861Sjhb normal_map = VFNT_MAP_NORMAL; 104262861Sjhb bold_map = VFNT_MAP_BOLD; 105262861Sjhb } 106262861Sjhb 107219888Sed if (TCHAR_FORMAT(c) & TF_BOLD) { 108262861Sjhb dst = vtfont_bisearch(vf->vf_map[bold_map], 109262861Sjhb vf->vf_map_count[bold_map], src); 110219888Sed if (dst != 0) 111219888Sed goto found; 112219888Sed } 113262861Sjhb dst = vtfont_bisearch(vf->vf_map[normal_map], 114262861Sjhb vf->vf_map_count[normal_map], src); 115219888Sed 116219888Sedfound: 117219888Sed stride = howmany(vf->vf_width, 8) * vf->vf_height; 118219888Sed return (&vf->vf_bytes[dst * stride]); 119219888Sed} 120219888Sed 121219888Sedstruct vt_font * 122219888Sedvtfont_ref(struct vt_font *vf) 123219888Sed{ 124219888Sed 125219888Sed refcount_acquire(&vf->vf_refcount); 126219888Sed return (vf); 127219888Sed} 128219888Sed 129219888Sedvoid 130219888Sedvtfont_unref(struct vt_font *vf) 131219888Sed{ 132262861Sjhb unsigned int i; 133219888Sed 134219888Sed if (refcount_release(&vf->vf_refcount)) { 135262861Sjhb for (i = 0; i < VFNT_MAPS; i++) 136262861Sjhb free(vf->vf_map[i], M_VTFONT); 137219888Sed free(vf->vf_bytes, M_VTFONT); 138219888Sed free(vf, M_VTFONT); 139219888Sed } 140219888Sed} 141219888Sed 142219888Sedstatic int 143219888Sedvtfont_validate_map(struct vt_font_map *vfm, unsigned int length, 144262861Sjhb unsigned int glyph_count) 145219888Sed{ 146219888Sed unsigned int i, last = 0; 147219888Sed 148219888Sed for (i = 0; i < length; i++) { 149219888Sed /* Not ordered. */ 150219888Sed if (i > 0 && vfm[i].vfm_src <= last) 151219888Sed return (EINVAL); 152219888Sed /* 153219888Sed * Destination extends amount of glyphs. 154219888Sed */ 155262861Sjhb if (vfm[i].vfm_dst >= glyph_count || 156262861Sjhb vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count) 157219888Sed return (EINVAL); 158219888Sed last = vfm[i].vfm_src + vfm[i].vfm_len; 159219888Sed } 160219888Sed 161219888Sed return (0); 162219888Sed} 163219888Sed 164219888Sedint 165219888Sedvtfont_load(vfnt_t *f, struct vt_font **ret) 166219888Sed{ 167262861Sjhb size_t glyphsize, mapsize; 168219888Sed struct vt_font *vf; 169219888Sed int error; 170262861Sjhb unsigned int i; 171219888Sed 172219888Sed /* Make sure the dimensions are valid. */ 173219888Sed if (f->width < 1 || f->height < 1) 174219888Sed return (EINVAL); 175331983Sgordon if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION || 176331983Sgordon f->glyph_count > VTFONT_MAXGLYPHS) 177219888Sed return (E2BIG); 178219888Sed 179219888Sed /* Not too many mappings. */ 180262861Sjhb for (i = 0; i < VFNT_MAPS; i++) 181262861Sjhb if (f->map_count[i] > VTFONT_MAXMAPPINGS) 182262861Sjhb return (E2BIG); 183256145Sray 184219888Sed /* Character 0 must always be present. */ 185262861Sjhb if (f->glyph_count < 1) 186219888Sed return (EINVAL); 187219888Sed 188262861Sjhb glyphsize = howmany(f->width, 8) * f->height * f->glyph_count; 189219888Sed if (glyphsize > VTFONT_MAXGLYPHSIZE) 190219888Sed return (E2BIG); 191219888Sed 192219888Sed /* Allocate new font structure. */ 193262861Sjhb vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO); 194219888Sed vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK); 195219888Sed vf->vf_height = f->height; 196219888Sed vf->vf_width = f->width; 197219888Sed vf->vf_refcount = 1; 198219888Sed 199262861Sjhb /* Allocate, copy in, and validate mappings. */ 200262861Sjhb for (i = 0; i < VFNT_MAPS; i++) { 201262861Sjhb vf->vf_map_count[i] = f->map_count[i]; 202262861Sjhb if (f->map_count[i] == 0) 203262861Sjhb continue; 204262861Sjhb mapsize = f->map_count[i] * sizeof(struct vt_font_map); 205262861Sjhb vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); 206262861Sjhb error = copyin(f->map[i], vf->vf_map[i], mapsize); 207262861Sjhb if (error) 208262861Sjhb goto bad; 209262861Sjhb error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i], 210262861Sjhb f->glyph_count); 211262861Sjhb if (error) 212262861Sjhb goto bad; 213262861Sjhb } 214262861Sjhb 215262861Sjhb /* Copy in glyph data. */ 216219888Sed error = copyin(f->glyphs, vf->vf_bytes, glyphsize); 217219888Sed if (error) 218219888Sed goto bad; 219219888Sed 220219888Sed /* Success. */ 221219888Sed *ret = vf; 222219888Sed return (0); 223219888Sed 224219888Sedbad: vtfont_unref(vf); 225219888Sed return (error); 226219888Sed} 227