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$"); 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. */ 44263817Sray#define VTFONT_MAXMAPPINGS 8192 45263817Sray#define VTFONT_MAXGLYPHSIZE 1048576 46219888Sed#define VTFONT_MAXDIMENSION 128 47219888Sed 48219888Sedstatic uint16_t 49219888Sedvtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) 50219888Sed{ 51219888Sed int min, mid, max; 52219888Sed 53219888Sed min = 0; 54219888Sed max = len - 1; 55219888Sed 56219888Sed /* Empty font map. */ 57219888Sed if (len == 0) 58219888Sed return (0); 59219888Sed /* Character below minimal entry. */ 60219888Sed if (src < map[0].vfm_src) 61219888Sed return (0); 62219888Sed /* Optimization: ASCII characters occur very often. */ 63219888Sed if (src <= map[0].vfm_src + map[0].vfm_len) 64219888Sed return (src - map[0].vfm_src + map[0].vfm_dst); 65219888Sed /* Character above maximum entry. */ 66219888Sed if (src > map[max].vfm_src + map[max].vfm_len) 67219888Sed return (0); 68219888Sed 69219888Sed /* Binary search. */ 70219888Sed while (max >= min) { 71219888Sed mid = (min + max) / 2; 72219888Sed if (src < map[mid].vfm_src) 73219888Sed max = mid - 1; 74219888Sed else if (src > map[mid].vfm_src + map[mid].vfm_len) 75219888Sed min = mid + 1; 76219888Sed else 77219888Sed return (src - map[mid].vfm_src + map[mid].vfm_dst); 78219888Sed } 79219888Sed 80219888Sed return (0); 81219888Sed} 82219888Sed 83219888Sedconst uint8_t * 84219888Sedvtfont_lookup(const struct vt_font *vf, term_char_t c) 85219888Sed{ 86219888Sed uint32_t src; 87219888Sed uint16_t dst; 88219888Sed size_t stride; 89263817Sray unsigned int normal_map; 90263817Sray unsigned int bold_map; 91219888Sed 92263817Sray /* 93263817Sray * No support for printing right hand sides for CJK fullwidth 94263817Sray * characters. Simply print a space and assume that the left 95263817Sray * hand side describes the entire character. 96263817Sray */ 97219888Sed src = TCHAR_CHARACTER(c); 98263817Sray if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) { 99263817Sray normal_map = VFNT_MAP_NORMAL_RIGHT; 100263817Sray bold_map = VFNT_MAP_BOLD_RIGHT; 101263817Sray } else { 102263817Sray normal_map = VFNT_MAP_NORMAL; 103263817Sray bold_map = VFNT_MAP_BOLD; 104263817Sray } 105263817Sray 106219888Sed if (TCHAR_FORMAT(c) & TF_BOLD) { 107263817Sray dst = vtfont_bisearch(vf->vf_map[bold_map], 108263817Sray vf->vf_map_count[bold_map], src); 109219888Sed if (dst != 0) 110219888Sed goto found; 111219888Sed } 112263817Sray dst = vtfont_bisearch(vf->vf_map[normal_map], 113263817Sray vf->vf_map_count[normal_map], src); 114219888Sed 115219888Sedfound: 116219888Sed stride = howmany(vf->vf_width, 8) * vf->vf_height; 117219888Sed return (&vf->vf_bytes[dst * stride]); 118219888Sed} 119219888Sed 120219888Sedstruct vt_font * 121219888Sedvtfont_ref(struct vt_font *vf) 122219888Sed{ 123219888Sed 124219888Sed refcount_acquire(&vf->vf_refcount); 125219888Sed return (vf); 126219888Sed} 127219888Sed 128219888Sedvoid 129219888Sedvtfont_unref(struct vt_font *vf) 130219888Sed{ 131263817Sray unsigned int i; 132219888Sed 133219888Sed if (refcount_release(&vf->vf_refcount)) { 134263817Sray for (i = 0; i < VFNT_MAPS; i++) 135263817Sray free(vf->vf_map[i], M_VTFONT); 136219888Sed free(vf->vf_bytes, M_VTFONT); 137219888Sed free(vf, M_VTFONT); 138219888Sed } 139219888Sed} 140219888Sed 141219888Sedstatic int 142219888Sedvtfont_validate_map(struct vt_font_map *vfm, unsigned int length, 143263817Sray unsigned int glyph_count) 144219888Sed{ 145219888Sed unsigned int i, last = 0; 146219888Sed 147219888Sed for (i = 0; i < length; i++) { 148219888Sed /* Not ordered. */ 149219888Sed if (i > 0 && vfm[i].vfm_src <= last) 150219888Sed return (EINVAL); 151219888Sed /* 152219888Sed * Destination extends amount of glyphs. 153219888Sed */ 154263817Sray if (vfm[i].vfm_dst >= glyph_count || 155263817Sray vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count) 156219888Sed return (EINVAL); 157219888Sed last = vfm[i].vfm_src + vfm[i].vfm_len; 158219888Sed } 159219888Sed 160219888Sed return (0); 161219888Sed} 162219888Sed 163219888Sedint 164219888Sedvtfont_load(vfnt_t *f, struct vt_font **ret) 165219888Sed{ 166263817Sray size_t glyphsize, mapsize; 167219888Sed struct vt_font *vf; 168219888Sed int error; 169263817Sray unsigned int i; 170219888Sed 171219888Sed /* Make sure the dimensions are valid. */ 172219888Sed if (f->width < 1 || f->height < 1) 173219888Sed return (EINVAL); 174219888Sed if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION) 175219888Sed return (E2BIG); 176219888Sed 177219888Sed /* Not too many mappings. */ 178263817Sray for (i = 0; i < VFNT_MAPS; i++) 179263817Sray if (f->map_count[i] > VTFONT_MAXMAPPINGS) 180263817Sray return (E2BIG); 181256145Sray 182219888Sed /* Character 0 must always be present. */ 183263817Sray if (f->glyph_count < 1) 184219888Sed return (EINVAL); 185219888Sed 186263817Sray glyphsize = howmany(f->width, 8) * f->height * f->glyph_count; 187219888Sed if (glyphsize > VTFONT_MAXGLYPHSIZE) 188219888Sed return (E2BIG); 189219888Sed 190219888Sed /* Allocate new font structure. */ 191263817Sray vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO); 192219888Sed vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK); 193219888Sed vf->vf_height = f->height; 194219888Sed vf->vf_width = f->width; 195219888Sed vf->vf_refcount = 1; 196219888Sed 197263817Sray /* Allocate, copy in, and validate mappings. */ 198263817Sray for (i = 0; i < VFNT_MAPS; i++) { 199263817Sray vf->vf_map_count[i] = f->map_count[i]; 200263817Sray if (f->map_count[i] == 0) 201263817Sray continue; 202263817Sray mapsize = f->map_count[i] * sizeof(struct vt_font_map); 203263817Sray vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); 204263817Sray error = copyin(f->map[i], vf->vf_map[i], mapsize); 205263817Sray if (error) 206263817Sray goto bad; 207263817Sray error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i], 208263817Sray f->glyph_count); 209263817Sray if (error) 210263817Sray goto bad; 211263817Sray } 212263817Sray 213263817Sray /* Copy in glyph data. */ 214219888Sed error = copyin(f->glyphs, vf->vf_bytes, glyphsize); 215219888Sed if (error) 216219888Sed goto bad; 217219888Sed 218219888Sed /* Success. */ 219219888Sed *ret = vf; 220219888Sed return (0); 221219888Sed 222219888Sedbad: vtfont_unref(vf); 223219888Sed return (error); 224219888Sed} 225