127cf7d04SAleksandr Rybalko /*- 2*718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*718cf2ccSPedro F. Giffuni * 427cf7d04SAleksandr Rybalko * Copyright (c) 2009 The FreeBSD Foundation 527cf7d04SAleksandr Rybalko * All rights reserved. 627cf7d04SAleksandr Rybalko * 727cf7d04SAleksandr Rybalko * This software was developed by Ed Schouten under sponsorship from the 827cf7d04SAleksandr Rybalko * FreeBSD Foundation. 927cf7d04SAleksandr Rybalko * 1027cf7d04SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 1127cf7d04SAleksandr Rybalko * modification, are permitted provided that the following conditions 1227cf7d04SAleksandr Rybalko * are met: 1327cf7d04SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 1427cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 1527cf7d04SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 1627cf7d04SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 1727cf7d04SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 1827cf7d04SAleksandr Rybalko * 1927cf7d04SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2027cf7d04SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2127cf7d04SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2227cf7d04SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2327cf7d04SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2427cf7d04SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2527cf7d04SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2627cf7d04SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2727cf7d04SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2827cf7d04SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2927cf7d04SAleksandr Rybalko * SUCH DAMAGE. 3027cf7d04SAleksandr Rybalko */ 3127cf7d04SAleksandr Rybalko 3227cf7d04SAleksandr Rybalko #include <sys/cdefs.h> 3327cf7d04SAleksandr Rybalko __FBSDID("$FreeBSD$"); 3427cf7d04SAleksandr Rybalko 3527cf7d04SAleksandr Rybalko #include <sys/param.h> 3627cf7d04SAleksandr Rybalko #include <sys/kernel.h> 3727cf7d04SAleksandr Rybalko #include <sys/malloc.h> 3827cf7d04SAleksandr Rybalko #include <sys/refcount.h> 3927cf7d04SAleksandr Rybalko #include <sys/systm.h> 4027cf7d04SAleksandr Rybalko 4127cf7d04SAleksandr Rybalko #include <dev/vt/vt.h> 4227cf7d04SAleksandr Rybalko 4327cf7d04SAleksandr Rybalko static MALLOC_DEFINE(M_VTFONT, "vtfont", "vt font"); 4427cf7d04SAleksandr Rybalko 4527cf7d04SAleksandr Rybalko /* Some limits to prevent abnormal fonts from being loaded. */ 46a04eaf90SEd Maste #define VTFONT_MAXMAPPINGS 65536 47a04eaf90SEd Maste #define VTFONT_MAXGLYPHSIZE 2097152 4827cf7d04SAleksandr Rybalko #define VTFONT_MAXDIMENSION 128 4927cf7d04SAleksandr Rybalko 5027cf7d04SAleksandr Rybalko static uint16_t 5127cf7d04SAleksandr Rybalko vtfont_bisearch(const struct vt_font_map *map, unsigned int len, uint32_t src) 5227cf7d04SAleksandr Rybalko { 5327cf7d04SAleksandr Rybalko int min, mid, max; 5427cf7d04SAleksandr Rybalko 5527cf7d04SAleksandr Rybalko min = 0; 5627cf7d04SAleksandr Rybalko max = len - 1; 5727cf7d04SAleksandr Rybalko 5827cf7d04SAleksandr Rybalko /* Empty font map. */ 5927cf7d04SAleksandr Rybalko if (len == 0) 6027cf7d04SAleksandr Rybalko return (0); 6127cf7d04SAleksandr Rybalko /* Character below minimal entry. */ 6227cf7d04SAleksandr Rybalko if (src < map[0].vfm_src) 6327cf7d04SAleksandr Rybalko return (0); 6427cf7d04SAleksandr Rybalko /* Optimization: ASCII characters occur very often. */ 6527cf7d04SAleksandr Rybalko if (src <= map[0].vfm_src + map[0].vfm_len) 6627cf7d04SAleksandr Rybalko return (src - map[0].vfm_src + map[0].vfm_dst); 6727cf7d04SAleksandr Rybalko /* Character above maximum entry. */ 6827cf7d04SAleksandr Rybalko if (src > map[max].vfm_src + map[max].vfm_len) 6927cf7d04SAleksandr Rybalko return (0); 7027cf7d04SAleksandr Rybalko 7127cf7d04SAleksandr Rybalko /* Binary search. */ 7227cf7d04SAleksandr Rybalko while (max >= min) { 7327cf7d04SAleksandr Rybalko mid = (min + max) / 2; 7427cf7d04SAleksandr Rybalko if (src < map[mid].vfm_src) 7527cf7d04SAleksandr Rybalko max = mid - 1; 7627cf7d04SAleksandr Rybalko else if (src > map[mid].vfm_src + map[mid].vfm_len) 7727cf7d04SAleksandr Rybalko min = mid + 1; 7827cf7d04SAleksandr Rybalko else 7927cf7d04SAleksandr Rybalko return (src - map[mid].vfm_src + map[mid].vfm_dst); 8027cf7d04SAleksandr Rybalko } 8127cf7d04SAleksandr Rybalko 8227cf7d04SAleksandr Rybalko return (0); 8327cf7d04SAleksandr Rybalko } 8427cf7d04SAleksandr Rybalko 8527cf7d04SAleksandr Rybalko const uint8_t * 8627cf7d04SAleksandr Rybalko vtfont_lookup(const struct vt_font *vf, term_char_t c) 8727cf7d04SAleksandr Rybalko { 8827cf7d04SAleksandr Rybalko uint32_t src; 8927cf7d04SAleksandr Rybalko uint16_t dst; 9027cf7d04SAleksandr Rybalko size_t stride; 9141fb0665SEd Maste unsigned int normal_map; 9241fb0665SEd Maste unsigned int bold_map; 9327cf7d04SAleksandr Rybalko 94a6c26592SEd Schouten /* 95a6c26592SEd Schouten * No support for printing right hand sides for CJK fullwidth 96a6c26592SEd Schouten * characters. Simply print a space and assume that the left 97a6c26592SEd Schouten * hand side describes the entire character. 98a6c26592SEd Schouten */ 9927cf7d04SAleksandr Rybalko src = TCHAR_CHARACTER(c); 10041fb0665SEd Maste if (TCHAR_FORMAT(c) & TF_CJK_RIGHT) { 10141fb0665SEd Maste normal_map = VFNT_MAP_NORMAL_RIGHT; 10241fb0665SEd Maste bold_map = VFNT_MAP_BOLD_RIGHT; 10341fb0665SEd Maste } else { 10441fb0665SEd Maste normal_map = VFNT_MAP_NORMAL; 10541fb0665SEd Maste bold_map = VFNT_MAP_BOLD; 10641fb0665SEd Maste } 107a6c26592SEd Schouten 10827cf7d04SAleksandr Rybalko if (TCHAR_FORMAT(c) & TF_BOLD) { 10941fb0665SEd Maste dst = vtfont_bisearch(vf->vf_map[bold_map], 11041fb0665SEd Maste vf->vf_map_count[bold_map], src); 11127cf7d04SAleksandr Rybalko if (dst != 0) 11227cf7d04SAleksandr Rybalko goto found; 11327cf7d04SAleksandr Rybalko } 11441fb0665SEd Maste dst = vtfont_bisearch(vf->vf_map[normal_map], 11541fb0665SEd Maste vf->vf_map_count[normal_map], src); 11627cf7d04SAleksandr Rybalko 11727cf7d04SAleksandr Rybalko found: 11827cf7d04SAleksandr Rybalko stride = howmany(vf->vf_width, 8) * vf->vf_height; 11927cf7d04SAleksandr Rybalko return (&vf->vf_bytes[dst * stride]); 12027cf7d04SAleksandr Rybalko } 12127cf7d04SAleksandr Rybalko 12227cf7d04SAleksandr Rybalko struct vt_font * 12327cf7d04SAleksandr Rybalko vtfont_ref(struct vt_font *vf) 12427cf7d04SAleksandr Rybalko { 12527cf7d04SAleksandr Rybalko 12627cf7d04SAleksandr Rybalko refcount_acquire(&vf->vf_refcount); 12727cf7d04SAleksandr Rybalko return (vf); 12827cf7d04SAleksandr Rybalko } 12927cf7d04SAleksandr Rybalko 13027cf7d04SAleksandr Rybalko void 13127cf7d04SAleksandr Rybalko vtfont_unref(struct vt_font *vf) 13227cf7d04SAleksandr Rybalko { 13341fb0665SEd Maste unsigned int i; 13427cf7d04SAleksandr Rybalko 13527cf7d04SAleksandr Rybalko if (refcount_release(&vf->vf_refcount)) { 13641fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) 13741fb0665SEd Maste free(vf->vf_map[i], M_VTFONT); 13827cf7d04SAleksandr Rybalko free(vf->vf_bytes, M_VTFONT); 13927cf7d04SAleksandr Rybalko free(vf, M_VTFONT); 14027cf7d04SAleksandr Rybalko } 14127cf7d04SAleksandr Rybalko } 14227cf7d04SAleksandr Rybalko 14327cf7d04SAleksandr Rybalko static int 14427cf7d04SAleksandr Rybalko vtfont_validate_map(struct vt_font_map *vfm, unsigned int length, 14541fb0665SEd Maste unsigned int glyph_count) 14627cf7d04SAleksandr Rybalko { 14727cf7d04SAleksandr Rybalko unsigned int i, last = 0; 14827cf7d04SAleksandr Rybalko 14927cf7d04SAleksandr Rybalko for (i = 0; i < length; i++) { 15027cf7d04SAleksandr Rybalko /* Not ordered. */ 15127cf7d04SAleksandr Rybalko if (i > 0 && vfm[i].vfm_src <= last) 15227cf7d04SAleksandr Rybalko return (EINVAL); 15327cf7d04SAleksandr Rybalko /* 15427cf7d04SAleksandr Rybalko * Destination extends amount of glyphs. 15527cf7d04SAleksandr Rybalko */ 15641fb0665SEd Maste if (vfm[i].vfm_dst >= glyph_count || 15741fb0665SEd Maste vfm[i].vfm_dst + vfm[i].vfm_len >= glyph_count) 15827cf7d04SAleksandr Rybalko return (EINVAL); 15927cf7d04SAleksandr Rybalko last = vfm[i].vfm_src + vfm[i].vfm_len; 16027cf7d04SAleksandr Rybalko } 16127cf7d04SAleksandr Rybalko 16227cf7d04SAleksandr Rybalko return (0); 16327cf7d04SAleksandr Rybalko } 16427cf7d04SAleksandr Rybalko 16527cf7d04SAleksandr Rybalko int 16627cf7d04SAleksandr Rybalko vtfont_load(vfnt_t *f, struct vt_font **ret) 16727cf7d04SAleksandr Rybalko { 16841fb0665SEd Maste size_t glyphsize, mapsize; 16927cf7d04SAleksandr Rybalko struct vt_font *vf; 17027cf7d04SAleksandr Rybalko int error; 17141fb0665SEd Maste unsigned int i; 17227cf7d04SAleksandr Rybalko 17327cf7d04SAleksandr Rybalko /* Make sure the dimensions are valid. */ 17427cf7d04SAleksandr Rybalko if (f->width < 1 || f->height < 1) 17527cf7d04SAleksandr Rybalko return (EINVAL); 17627cf7d04SAleksandr Rybalko if (f->width > VTFONT_MAXDIMENSION || f->height > VTFONT_MAXDIMENSION) 17727cf7d04SAleksandr Rybalko return (E2BIG); 17827cf7d04SAleksandr Rybalko 17927cf7d04SAleksandr Rybalko /* Not too many mappings. */ 18041fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) 18141fb0665SEd Maste if (f->map_count[i] > VTFONT_MAXMAPPINGS) 18227cf7d04SAleksandr Rybalko return (E2BIG); 18327cf7d04SAleksandr Rybalko 18427cf7d04SAleksandr Rybalko /* Character 0 must always be present. */ 18541fb0665SEd Maste if (f->glyph_count < 1) 18627cf7d04SAleksandr Rybalko return (EINVAL); 18727cf7d04SAleksandr Rybalko 18841fb0665SEd Maste glyphsize = howmany(f->width, 8) * f->height * f->glyph_count; 18927cf7d04SAleksandr Rybalko if (glyphsize > VTFONT_MAXGLYPHSIZE) 19027cf7d04SAleksandr Rybalko return (E2BIG); 19127cf7d04SAleksandr Rybalko 19227cf7d04SAleksandr Rybalko /* Allocate new font structure. */ 19341fb0665SEd Maste vf = malloc(sizeof *vf, M_VTFONT, M_WAITOK | M_ZERO); 19427cf7d04SAleksandr Rybalko vf->vf_bytes = malloc(glyphsize, M_VTFONT, M_WAITOK); 19527cf7d04SAleksandr Rybalko vf->vf_height = f->height; 19627cf7d04SAleksandr Rybalko vf->vf_width = f->width; 19727cf7d04SAleksandr Rybalko vf->vf_refcount = 1; 19827cf7d04SAleksandr Rybalko 19941fb0665SEd Maste /* Allocate, copy in, and validate mappings. */ 20041fb0665SEd Maste for (i = 0; i < VFNT_MAPS; i++) { 20141fb0665SEd Maste vf->vf_map_count[i] = f->map_count[i]; 20241fb0665SEd Maste if (f->map_count[i] == 0) 20341fb0665SEd Maste continue; 20441fb0665SEd Maste mapsize = f->map_count[i] * sizeof(struct vt_font_map); 20541fb0665SEd Maste vf->vf_map[i] = malloc(mapsize, M_VTFONT, M_WAITOK); 20641fb0665SEd Maste error = copyin(f->map[i], vf->vf_map[i], mapsize); 20727cf7d04SAleksandr Rybalko if (error) 20827cf7d04SAleksandr Rybalko goto bad; 20941fb0665SEd Maste error = vtfont_validate_map(vf->vf_map[i], vf->vf_map_count[i], 21041fb0665SEd Maste f->glyph_count); 21127cf7d04SAleksandr Rybalko if (error) 21227cf7d04SAleksandr Rybalko goto bad; 21341fb0665SEd Maste } 21427cf7d04SAleksandr Rybalko 21541fb0665SEd Maste /* Copy in glyph data. */ 21641fb0665SEd Maste error = copyin(f->glyphs, vf->vf_bytes, glyphsize); 21727cf7d04SAleksandr Rybalko if (error) 21827cf7d04SAleksandr Rybalko goto bad; 21927cf7d04SAleksandr Rybalko 22027cf7d04SAleksandr Rybalko /* Success. */ 22127cf7d04SAleksandr Rybalko *ret = vf; 22227cf7d04SAleksandr Rybalko return (0); 22327cf7d04SAleksandr Rybalko 22427cf7d04SAleksandr Rybalko bad: vtfont_unref(vf); 22527cf7d04SAleksandr Rybalko return (error); 22627cf7d04SAleksandr Rybalko } 227