1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2014 David Herrmann <dh.herrmann@gmail.com>
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 * This implements the unifont glyph-array parser and provides it via a simple
25 * API to the caller. No heavy transformations are performed so glyph-lookups
26 * stay as fast as possible.
36 #include "unifont-def.h"
47 unifont_header header;
48 const void *glyphs; /* unaligned! */
53 static int unifont_fetch_header(unifont *u) {
54 unifont_header h = { };
57 if (u->size < UNIFONT_HEADER_SIZE_MIN)
60 assert_cc(sizeof(h) >= UNIFONT_HEADER_SIZE_MIN);
61 memcpy(&h, u->map, UNIFONT_HEADER_SIZE_MIN);
63 h.compatible_flags = le32toh(h.compatible_flags);
64 h.incompatible_flags = le32toh(h.incompatible_flags);
65 h.header_size = le32toh(h.header_size);
66 h.glyph_header_size = le16toh(h.glyph_header_size);
67 h.glyph_stride = le16toh(h.glyph_stride);
68 h.glyph_body_size = le64toh(h.glyph_body_size);
70 if (memcmp(h.signature, "DVDHRMUF", 8))
72 if (h.incompatible_flags != 0)
74 if (h.header_size < UNIFONT_HEADER_SIZE_MIN || h.header_size > u->size)
76 if (h.glyph_header_size + h.glyph_body_size < h.glyph_header_size)
78 if (h.glyph_stride * 16ULL > h.glyph_body_size)
81 glyphsize = h.glyph_header_size + h.glyph_body_size;
83 if (glyphsize == 0 || glyphsize > u->size - h.header_size) {
86 u->glyphs = u->map + h.header_size;
87 u->n_glyphs = (u->size - h.header_size) / glyphsize;
88 u->glyphsize = glyphsize;
91 memcpy(&u->header, &h, sizeof(h));
95 static int unifont_fetch_glyph(unifont *u, unifont_glyph_header *out_header, const void **out_body, uint32_t ucs4) {
96 unifont_glyph_header glyph_header = { };
97 const void *glyph_body = NULL;
100 if (ucs4 >= u->n_glyphs)
105 /* copy glyph-header data */
106 p += ucs4 * u->glyphsize;
107 memcpy(&glyph_header, p, MIN(sizeof(glyph_header), u->header.glyph_header_size));
109 /* copy glyph-body pointer */
110 p += u->header.glyph_header_size;
113 if (glyph_header.width < 1)
115 if (glyph_header.width > u->header.glyph_stride)
118 memcpy(out_header, &glyph_header, sizeof(glyph_header));
119 *out_body = glyph_body;
123 int unifont_new(unifont **out) {
124 _cleanup_(unifont_unrefp) unifont *u = NULL;
128 assert_return(out, -EINVAL);
130 u = new0(unifont, 1);
138 u->fd = open(UNIFONT_PATH, O_RDONLY | O_CLOEXEC | O_NOCTTY);
142 r = fstat(u->fd, &st);
146 u->size = st.st_size;
147 u->map = mmap(NULL, u->size, PROT_READ, MAP_PRIVATE, u->fd, 0);
148 if (u->map == MAP_FAILED)
151 r = unifont_fetch_header(u);
160 unifont *unifont_ref(unifont *u) {
169 unifont *unifont_unref(unifont *u) {
170 if (!u || !u->ref || --u->ref)
173 if (u->map != MAP_FAILED)
174 munmap((void*)u->map, u->size);
175 u->fd = safe_close(u->fd);
181 unsigned int unifont_get_width(unifont *u) {
187 unsigned int unifont_get_height(unifont *u) {
193 unsigned int unifont_get_stride(unifont *u) {
196 return u->header.glyph_stride;
199 int unifont_lookup(unifont *u, unifont_glyph *out, uint32_t ucs4) {
200 unifont_glyph_header h = { };
201 const void *b = NULL;
202 unifont_glyph g = { };
205 assert_return(u, -EINVAL);
207 r = unifont_fetch_glyph(u, &h, &b, ucs4);
211 g.width = h.width * 8U;
213 g.stride = u->header.glyph_stride;
218 memcpy(out, &g, sizeof(g));
222 void unifont_fallback(unifont_glyph *out) {
223 static const uint8_t fallback_data[] = {
224 /* unifont 0xfffd '�' (unicode replacement character) */
225 0x00, 0x00, 0x00, 0x7e,
226 0x66, 0x5a, 0x5a, 0x7a,
227 0x76, 0x76, 0x7e, 0x76,
228 0x76, 0x7e, 0x00, 0x00,
237 out->data = fallback_data;