127cf7d04SAleksandr Rybalko /*- 227cf7d04SAleksandr Rybalko * Copyright (c) 2009 The FreeBSD Foundation 327cf7d04SAleksandr Rybalko * All rights reserved. 427cf7d04SAleksandr Rybalko * 527cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the 627cf7d04SAleksandr Rybalko * FreeBSD Foundation. 727cf7d04SAleksandr Rybalko * 827cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 927cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1027cf7d04SAleksandr Rybalko * are met: 1127cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1227cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1327cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1427cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1527cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 1627cf7d04SAleksandr Rybalko * 1727cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1827cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1927cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2027cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2127cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2227cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2327cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2427cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2527cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2627cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2727cf7d04SAleksandr Rybalko * SUCH DAMAGE. 2827cf7d04SAleksandr Rybalko */ 2927cf7d04SAleksandr Rybalko 3027cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 3127cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3227cf7d04SAleksandr Rybalko 3327cf7d04SAleksandr Rybalko #include <sys/param.h> 3427cf7d04SAleksandr Rybalko #include <sys/kernel.h> 3527cf7d04SAleksandr Rybalko #include <sys/malloc.h> 3627cf7d04SAleksandr Rybalko #include <sys/refcount.h> 3727cf7d04SAleksandr Rybalko #include <sys/systm.h> 3827cf7d04SAleksandr Rybalko 3927cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 4027cf7d04SAleksandr Rybalko 4127cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font"); 4227cf7d04SAleksandr Rybalko 4327cf7d04SAleksandr Rybalko /* Some limits to prevent abnormal fonts from being loaded. */ 44*41fb0665SEd Maste #define VTFONT_MAXMAPPINGS 8192 4527cf7d04SAleksandr Rybalko #define VTFONT_MAXGLYPHSIZE 262144 4627cf7d04SAleksandr Rybalko #define VTFONT_MAXDIMENSION 128 4727cf7d04SAleksandr Rybalko 4827cf7d04SAleksandr Rybalko static uint16_t 4927cf7d04SAleksandr Rybalko vtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) 5027cf7d04SAleksandr Rybalko { 5127cf7d04SAleksandr Rybalko int min, mid, max; 5227cf7d04SAleksandr Rybalko 5327cf7d04SAleksandr Rybalko min = 0; 5427cf7d04SAleksandr Rybalko max = len - 1; 5527cf7d04SAleksandr Rybalko 5627cf7d04SAleksandr Rybalko /* Empty font map. */ 5727cf7d04SAleksandr Rybalko if (len == 0) 5827cf7d04SAleksandr Rybalko return (0); 5927cf7d04SAleksandr Rybalko /* Character below minimal entry. */ 6027cf7d04SAleksandr Rybalko if (src < map[0].vfm_src) 6127cf7d04SAleksandr Rybalko return (0); 6227cf7d04SAleksandr Rybalko /* Optimization: ASCII characters occur very often. */ 6327cf7d04SAleksandr Rybalko if (src <= map[0].vfm_src + map[0].vfm_len) 6427cf7d04SAleksandr Rybalko return (src - map[0].vfm_src + map[0].vfm_dst); 6527cf7d04SAleksandr Rybalko /* Character above maximum entry. */ 6627cf7d04SAleksandr Rybalko if (src > map[max].vfm_src + map[max].vfm_len) 6727cf7d04SAleksandr Rybalko return (0); 6827cf7d04SAleksandr Rybalko 6927cf7d04SAleksandr Rybalko /* Binary search. */ 7027cf7d04SAleksandr Rybalko while (max >= min) { 7127cf7d04SAleksandr Rybalko mid = (min + max) / 2; 7227cf7d04SAleksandr Rybalko if (src < map[mid].vfm_src) 7327cf7d04SAleksandr Rybalko max = mid - 1; 7427cf7d04SAleksandr Rybalko else if (src > map[mid].vfm_src + map[mid].vfm_len) 7527cf7d04SAleksandr Rybalko min = mid + 1; 7627cf7d04SAleksandr Rybalko else 7727cf7d04SAleksandr Rybalko return (src - map[mid].vfm_src + map[mid].vfm_dst); 7827cf7d04SAleksandr Rybalko } 7927cf7d04SAleksandr Rybalko 8027cf7d04SAleksandr Rybalko return (0); 8127cf7d04SAleksandr Rybalko } 8227cf7d04SAleksandr Rybalko 8327cf7d04SAleksandr Rybalko const uint8_t * 8427cf7d04SAleksandr Rybalko vtfont_lookup(const struct vt_font *vf, term_char_t c) 8527cf7d04SAleksandr Rybalko { 8627cf7d04SAleksandr Rybalko uint32_t src; 8727cf7d04SAleksandr Rybalko uint16_t dst; 8827cf7d04SAleksandr Rybalko size_t stride; 89*41fb0665SEd Maste unsigned int normal_map; 90*41fb0665SEd Maste unsigned int bold_map; 9127cf7d04SAleksandr Rybalko 92a6c26592SEd Schouten /* 93a6c26592SEd Schouten * No support for printing right hand sides for CJK fullwidth 94a6c26592SEd Schouten * characters. Simply print a space and assume that the left 95a6c26592SEd Schouten * hand side describes the entire character. 96a6c26592SEd Schouten */ 9727cf7d04SAleksandr Rybalko src = TCHAR_CHARACTER(c); 98*41fb0665SEd Maste if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) { 99*41fb0665SEd Maste normal_map = VFNT_MAP_NORMAL_RIGHT; 100*41fb0665SEd Maste bold_map = VFNT_MAP_BOLD_RIGHT; 101*41fb0665SEd Maste } else { 102*41fb0665SEd Maste normal_map = VFNT_MAP_NORMAL; 103*41fb0665SEd Maste bold_map = VFNT_MAP_BOLD; 104*41fb0665SEd Maste } 105a6c26592SEd Schouten 10627cf7d04SAleksandr Rybalko if (TCHAR_FORMAT(c) & TF_BOLD) { 107*41fb0665SEd Maste dst = vtfont_bisearch(vf->vf_map[bold_map], 108*41fb0665SEd Maste vf->vf_map_count[bold_map], src); 10927cf7d04SAleksandr Rybalko if (dst != 0) 11027cf7d04SAleksandr Rybalko goto found; 11127cf7d04SAleksandr Rybalko } 112*41fb0665SEd Maste dst = vtfont_bisearch(vf->vf_map[normal_map], 113*41fb0665SEd Maste vf->vf_map_count[normal_map], src); 11427cf7d04SAleksandr Rybalko 11527cf7d04SAleksandr Rybalko found: 11627cf7d04SAleksandr Rybalko stride = howmany(vf->vf_width, 8) * vf->vf_height; 11727cf7d04SAleksandr Rybalko return (&vf->vf_bytes[dst * stride]); 11827cf7d04SAleksandr Rybalko } 11927cf7d04SAleksandr Rybalko 12027cf7d04SAleksandr Rybalko struct vt_font * 12127cf7d04SAleksandr Rybalko vtfont_ref(struct vt_font *vf) 12227cf7d04SAleksandr Rybalko { 12327cf7d04SAleksandr Rybalko 12427cf7d04SAleksandr Rybalko refcount_acquire(&vf->vf_refcount); 12527cf7d04SAleksandr Rybalko return (vf); 12627cf7d04SAleksandr Rybalko } 12727cf7d04SAleksandr Rybalko 12827cf7d04SAleksandr Rybalko void 12927cf7d04SAleksandr Rybalko vtfont_unref(struct vt_font *vf) 13027cf7d04SAleksandr Rybalko { 131*41fb0665SEd Maste unsigned int i; 13227cf7d04SAleksandr Rybalko 13327cf7d04SAleksandr Rybalko if (refcount_release(&vf->vf_refcount)) { 134*41fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) 135*41fb0665SEd Maste free(vf->vf_map[i], M_VTFONT); 13627cf7d04SAleksandr Rybalko free(vf->vf_bytes, M_VTFONT); 13727cf7d04SAleksandr Rybalko free(vf, M_VTFONT); 13827cf7d04SAleksandr Rybalko } 13927cf7d04SAleksandr Rybalko } 14027cf7d04SAleksandr Rybalko 14127cf7d04SAleksandr Rybalko static int 14227cf7d04SAleksandr Rybalko vtfont_validate_map(struct vt_font_map *vfm, unsigned int length, 143*41fb0665SEd Maste unsigned int glyph_count) 14427cf7d04SAleksandr Rybalko { 14527cf7d04SAleksandr Rybalko unsigned int i, last = 0; 14627cf7d04SAleksandr Rybalko 14727cf7d04SAleksandr Rybalko for (i = 0; i < length; i++) { 14827cf7d04SAleksandr Rybalko /* Not ordered. */ 14927cf7d04SAleksandr Rybalko if (i > 0 && vfm[i].vfm_src <= last) 15027cf7d04SAleksandr Rybalko return (EINVAL); 15127cf7d04SAleksandr Rybalko /* 15227cf7d04SAleksandr Rybalko * Destination extends amount of glyphs. 15327cf7d04SAleksandr Rybalko */ 154*41fb0665SEd Maste if (vfm[i].vfm_dst >= glyph_count || 155*41fb0665SEd Maste vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count) 15627cf7d04SAleksandr Rybalko return (EINVAL); 15727cf7d04SAleksandr Rybalko last = vfm[i].vfm_src + vfm[i].vfm_len; 15827cf7d04SAleksandr Rybalko } 15927cf7d04SAleksandr Rybalko 16027cf7d04SAleksandr Rybalko return (0); 16127cf7d04SAleksandr Rybalko } 16227cf7d04SAleksandr Rybalko 16327cf7d04SAleksandr Rybalko int 16427cf7d04SAleksandr Rybalko vtfont_load(vfnt_t *f, struct vt_font **ret) 16527cf7d04SAleksandr Rybalko { 166*41fb0665SEd Maste size_t glyphsize, mapsize; 16727cf7d04SAleksandr Rybalko struct vt_font *vf; 16827cf7d04SAleksandr Rybalko int error; 169*41fb0665SEd Maste unsigned int i; 17027cf7d04SAleksandr Rybalko 17127cf7d04SAleksandr Rybalko /* Make sure the dimensions are valid. */ 17227cf7d04SAleksandr Rybalko if (f->width < 1 || f->height < 1) 17327cf7d04SAleksandr Rybalko return (EINVAL); 17427cf7d04SAleksandr Rybalko if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION) 17527cf7d04SAleksandr Rybalko return (E2BIG); 17627cf7d04SAleksandr Rybalko 17727cf7d04SAleksandr Rybalko /* Not too many mappings. */ 178*41fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) 179*41fb0665SEd Maste if (f->map_count[i] > VTFONT_MAXMAPPINGS) 18027cf7d04SAleksandr Rybalko return (E2BIG); 18127cf7d04SAleksandr Rybalko 18227cf7d04SAleksandr Rybalko /* Character 0 must always be present. */ 183*41fb0665SEd Maste if (f->glyph_count < 1) 18427cf7d04SAleksandr Rybalko return (EINVAL); 18527cf7d04SAleksandr Rybalko 186*41fb0665SEd Maste glyphsize = howmany(f->width, 8) * f->height * f->glyph_count; 18727cf7d04SAleksandr Rybalko if (glyphsize > VTFONT_MAXGLYPHSIZE) 18827cf7d04SAleksandr Rybalko return (E2BIG); 18927cf7d04SAleksandr Rybalko 19027cf7d04SAleksandr Rybalko /* Allocate new font structure. */ 191*41fb0665SEd Maste vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO); 19227cf7d04SAleksandr Rybalko vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK); 19327cf7d04SAleksandr Rybalko vf->vf_height = f->height; 19427cf7d04SAleksandr Rybalko vf->vf_width = f->width; 19527cf7d04SAleksandr Rybalko vf->vf_refcount = 1; 19627cf7d04SAleksandr Rybalko 197*41fb0665SEd Maste /* Allocate, copy in, and validate mappings. */ 198*41fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) { 199*41fb0665SEd Maste vf->vf_map_count[i] = f->map_count[i]; 200*41fb0665SEd Maste if (f->map_count[i] == 0) 201*41fb0665SEd Maste continue; 202*41fb0665SEd Maste mapsize = f->map_count[i] * sizeof(struct vt_font_map); 203*41fb0665SEd Maste vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); 204*41fb0665SEd Maste error = copyin(f->map[i], vf->vf_map[i], mapsize); 20527cf7d04SAleksandr Rybalko if (error) 20627cf7d04SAleksandr Rybalko goto bad; 207*41fb0665SEd Maste error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i], 208*41fb0665SEd Maste f->glyph_count); 20927cf7d04SAleksandr Rybalko if (error) 21027cf7d04SAleksandr Rybalko goto bad; 211*41fb0665SEd Maste } 21227cf7d04SAleksandr Rybalko 213*41fb0665SEd Maste /* Copy in glyph data. */ 214*41fb0665SEd Maste error = copyin(f->glyphs, vf->vf_bytes, glyphsize); 21527cf7d04SAleksandr Rybalko if (error) 21627cf7d04SAleksandr Rybalko goto bad; 21727cf7d04SAleksandr Rybalko 21827cf7d04SAleksandr Rybalko /* Success. */ 21927cf7d04SAleksandr Rybalko *ret = vf; 22027cf7d04SAleksandr Rybalko return (0); 22127cf7d04SAleksandr Rybalko 22227cf7d04SAleksandr Rybalko bad: vtfont_unref(vf); 22327cf7d04SAleksandr Rybalko return (error); 22427cf7d04SAleksandr Rybalko } 225