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