]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - tools/tools/vt/fontcvt/fontcvt.c
MFC 267883:
[FreeBSD/stable/10.git] / tools / tools / vt / fontcvt / fontcvt.c
1 /*-
2  * Copyright (c) 2009 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Ed Schouten under sponsorship from the
6  * FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <sys/endian.h>
34 #include <sys/param.h>
35 #include <sys/queue.h>
36
37 #include <assert.h>
38 #include <stdint.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 #define VFNT_MAPS 4
44 #define VFNT_MAP_NORMAL 0
45 #define VFNT_MAP_BOLD 2
46
47 static unsigned int width, wbytes, height;
48
49 struct glyph {
50         TAILQ_ENTRY(glyph)       g_list;
51         uint8_t                 *g_data;
52         unsigned int             g_index;
53 };
54
55 TAILQ_HEAD(glyph_list, glyph);
56 static struct glyph_list glyphs[VFNT_MAPS] = {
57     TAILQ_HEAD_INITIALIZER(glyphs[0]),
58     TAILQ_HEAD_INITIALIZER(glyphs[1]),
59     TAILQ_HEAD_INITIALIZER(glyphs[2]),
60     TAILQ_HEAD_INITIALIZER(glyphs[3]),
61 };
62 static unsigned int glyph_total, glyph_count[4], glyph_unique, glyph_dupe;
63
64 struct mapping {
65         TAILQ_ENTRY(mapping)     m_list;
66         unsigned int             m_char;
67         unsigned int             m_length;
68         struct glyph            *m_glyph;
69 };
70
71 TAILQ_HEAD(mapping_list, mapping);
72 static struct mapping_list maps[VFNT_MAPS] = {
73     TAILQ_HEAD_INITIALIZER(maps[0]),
74     TAILQ_HEAD_INITIALIZER(maps[1]),
75     TAILQ_HEAD_INITIALIZER(maps[2]),
76     TAILQ_HEAD_INITIALIZER(maps[3]),
77 };
78 static unsigned int mapping_total, map_count[4], map_folded_count[4],
79     mapping_unique, mapping_dupe;
80
81 static void
82 usage(void)
83 {
84
85         fprintf(stderr,
86 "usage: fontcvt width height normal.bdf bold.bdf out.fnt\n");
87         exit(1);
88 }
89
90 static int
91 add_mapping(struct glyph *gl, unsigned int c, unsigned int map_idx)
92 {
93         struct mapping *mp;
94         struct mapping_list *ml;
95
96         mapping_total++;
97
98         if (map_idx >= VFNT_MAP_BOLD) {
99                 int found = 0;
100                 unsigned normal_map_idx = map_idx - VFNT_MAP_BOLD;
101
102                 TAILQ_FOREACH(mp, &maps[normal_map_idx], m_list) {
103                         if (mp->m_char < c)
104                                 continue;
105                         else if (mp->m_char > c)
106                                 break;
107                         found = 1;
108
109                         /*
110                          * No mapping is needed if it's equal to the
111                          * normal mapping.
112                          */
113                         if (mp->m_glyph == gl) {
114                                 mapping_dupe++;
115                                 return (0);
116                         }
117                 }
118
119                 if (!found) {
120                         fprintf(stderr,
121                             "Character %u not in normal font!\n", c);
122                         return (1);
123                 }
124         }
125
126         mp = malloc(sizeof *mp);
127         mp->m_char = c;
128         mp->m_glyph = gl;
129         mp->m_length = 0;
130
131         ml = &maps[map_idx];
132         if (TAILQ_LAST(ml, mapping_list) != NULL &&
133             TAILQ_LAST(ml, mapping_list)->m_char >= c) {
134                 fprintf(stderr, "Bad ordering at character %u\n", c);
135                 return (1);
136         }
137         TAILQ_INSERT_TAIL(ml, mp, m_list);
138
139         map_count[map_idx]++;
140         mapping_unique++;
141
142         return (0);
143 }
144
145 static struct glyph *
146 add_glyph(const uint8_t *bytes, unsigned int map_idx, int fallback)
147 {
148         struct glyph *gl;
149         unsigned int i;
150
151         glyph_total++;
152         glyph_count[map_idx]++;
153
154         for (i = 0; i < VFNT_MAPS; i++) {
155                 TAILQ_FOREACH(gl, &glyphs[i], g_list) {
156                         if (memcmp(gl->g_data, bytes, wbytes * height) == 0) {
157                                 glyph_dupe++;
158                                 return (gl);
159                         }
160                 }
161         }
162
163         gl = malloc(sizeof *gl);
164         gl->g_data = malloc(wbytes * height);
165         memcpy(gl->g_data, bytes, wbytes * height);
166         if (fallback)
167                 TAILQ_INSERT_HEAD(&glyphs[map_idx], gl, g_list);
168         else
169                 TAILQ_INSERT_TAIL(&glyphs[map_idx], gl, g_list);
170
171         glyph_unique++;
172         return (gl);
173 }
174
175 static int
176 parse_bitmap_line(uint8_t *left, uint8_t *right, unsigned int line,
177     unsigned int dwidth)
178 {
179         uint8_t *p;
180         unsigned int i, subline;
181
182         if (dwidth != width && dwidth != width * 2) {
183                 fprintf(stderr,
184                     "Unsupported width %u!\n", dwidth);
185                 return (1);
186         }
187
188         /* Move pixel data right to simplify splitting double characters. */
189         line >>= (howmany(dwidth, 8) * 8) - dwidth;
190
191         for (i = dwidth / width; i > 0; i--) {
192                 p = (i == 2) ? right : left;
193
194                 subline = line & ((1 << width) - 1);
195                 subline <<= (howmany(width, 8) * 8) - width;
196
197                 if (wbytes == 1) {
198                         *p = subline;
199                 } else if (wbytes == 2) {
200                         *p++ = subline >> 8;
201                         *p = subline;
202                 } else {
203                         fprintf(stderr,
204                             "Unsupported wbytes %u!\n", wbytes);
205                         return (1);
206                 }
207
208                 line >>= width;
209         }
210         
211         return (0);
212 }
213
214 static int
215 parse_bdf(const char *filename, unsigned int map_idx)
216 {
217         FILE *fp;
218         char *ln;
219         size_t length;
220         uint8_t bytes[wbytes * height], bytes_r[wbytes * height];
221         unsigned int curchar = 0, dwidth = 0, i, line;
222         struct glyph *gl;
223
224         fp = fopen(filename, "r");
225         if (fp == NULL) {
226                 perror(filename);
227                 return (1);
228         }
229
230         while ((ln = fgetln(fp, &length)) != NULL) {
231                 ln[length - 1] = '\0';
232
233                 if (strncmp(ln, "ENCODING ", 9) == 0) {
234                         curchar = atoi(ln + 9);
235                 }
236
237                 if (strncmp(ln, "DWIDTH ", 7) == 0) {
238                         dwidth = atoi(ln + 7);
239                 }
240
241                 if (strcmp(ln, "BITMAP") == 0) {
242                         for (i = 0; i < height; i++) {
243                                 if ((ln = fgetln(fp, &length)) == NULL) {
244                                         fprintf(stderr, "Unexpected EOF!\n");
245                                         return (1);
246                                 }
247                                 ln[length - 1] = '\0';
248                                 sscanf(ln, "%x", &line);
249                                 if (parse_bitmap_line(bytes + i * wbytes,
250                                      bytes_r + i * wbytes, line, dwidth) != 0)
251                                         return (1);
252                         }
253
254                         /* Prevent adding two glyphs for 0xFFFD */
255                         if (curchar == 0xFFFD) {
256                                 if (map_idx < VFNT_MAP_BOLD)
257                                         gl = add_glyph(bytes, 0, 1);
258                         } else if (curchar >= 0x20) {
259                                 gl = add_glyph(bytes, map_idx, 0);
260                                 if (add_mapping(gl, curchar, map_idx) != 0)
261                                         return (1);
262                                 if (dwidth == width * 2) {
263                                         gl = add_glyph(bytes_r, map_idx + 1, 0);
264                                         if (add_mapping(gl, curchar,
265                                             map_idx + 1) != 0)
266                                                 return (1);
267                                 }
268                         }
269                 }
270         }
271
272         return (0);
273 }
274
275 static void
276 number_glyphs(void)
277 {
278         struct glyph *gl;
279         unsigned int i, idx = 0;
280
281         for (i = 0; i < VFNT_MAPS; i++)
282                 TAILQ_FOREACH(gl, &glyphs[i], g_list)
283                         gl->g_index = idx++;
284 }
285
286 static void
287 write_glyphs(FILE *fp)
288 {
289         struct glyph *gl;
290         unsigned int i;
291
292         for (i = 0; i < VFNT_MAPS; i++) {
293                 TAILQ_FOREACH(gl, &glyphs[i], g_list)
294                         fwrite(gl->g_data, wbytes * height, 1, fp);
295         }
296 }
297
298 static void
299 fold_mappings(unsigned int map_idx)
300 {
301         struct mapping_list *ml = &maps[map_idx];
302         struct mapping *mn, *mp, *mbase;
303
304         mp = mbase = TAILQ_FIRST(ml);
305         for (mp = mbase = TAILQ_FIRST(ml); mp != NULL; mp = mn) {
306                 mn = TAILQ_NEXT(mp, m_list);
307                 if (mn != NULL && mn->m_char == mp->m_char + 1 &&
308                     mn->m_glyph->g_index == mp->m_glyph->g_index + 1)
309                         continue;
310                 mbase->m_length = mp->m_char - mbase->m_char + 1;
311                 mbase = mp = mn;
312                 map_folded_count[map_idx]++;
313         }
314 }
315
316 struct file_mapping {
317         uint32_t        source;
318         uint16_t        destination;
319         uint16_t        length;
320 } __packed;
321
322 static void
323 write_mappings(FILE *fp, unsigned int map_idx)
324 {
325         struct mapping_list *ml = &maps[map_idx];
326         struct mapping *mp;
327         struct file_mapping fm;
328         unsigned int i = 0, j = 0;
329
330         TAILQ_FOREACH(mp, ml, m_list) {
331                 j++;
332                 if (mp->m_length > 0) {
333                         i += mp->m_length;
334                         fm.source = htobe32(mp->m_char);
335                         fm.destination = htobe16(mp->m_glyph->g_index);
336                         fm.length = htobe16(mp->m_length - 1);
337                         fwrite(&fm, sizeof fm, 1, fp);
338                 }
339         }
340         assert(i == j);
341 }
342
343 struct file_header {
344         uint8_t         magic[8];
345         uint8_t         width;
346         uint8_t         height;
347         uint16_t        pad;
348         uint32_t        glyph_count;
349         uint32_t        map_count[4];
350 } __packed;
351
352 static int
353 write_fnt(const char *filename)
354 {
355         FILE *fp;
356         struct file_header fh = {
357                 .magic = "VFNT0002",
358         };
359
360         fp = fopen(filename, "wb");
361         if (fp == NULL) {
362                 perror(filename);
363                 return (1);
364         }
365
366         fh.width = width;
367         fh.height = height;
368         fh.glyph_count = htobe32(glyph_unique);
369         fh.map_count[0] = htobe32(map_folded_count[0]);
370         fh.map_count[1] = htobe32(map_folded_count[1]);
371         fh.map_count[2] = htobe32(map_folded_count[2]);
372         fh.map_count[3] = htobe32(map_folded_count[3]);
373         fwrite(&fh, sizeof fh, 1, fp);
374         
375         write_glyphs(fp);
376         write_mappings(fp, VFNT_MAP_NORMAL);
377         write_mappings(fp, 1);
378         write_mappings(fp, VFNT_MAP_BOLD);
379         write_mappings(fp, 3);
380
381         return (0);
382 }
383
384 int
385 main(int argc, char *argv[])
386 {
387
388         assert(sizeof(struct file_header) == 32);
389         assert(sizeof(struct file_mapping) == 8);
390
391         if (argc != 6)
392                 usage();
393         
394         width = atoi(argv[1]);
395         wbytes = howmany(width, 8);
396         height = atoi(argv[2]);
397
398         if (parse_bdf(argv[3], VFNT_MAP_NORMAL) != 0)
399                 return (1);
400         if (parse_bdf(argv[4], VFNT_MAP_BOLD) != 0)
401                 return (1);
402         number_glyphs();
403         fold_mappings(0);
404         fold_mappings(1);
405         fold_mappings(2);
406         fold_mappings(3);
407         if (write_fnt(argv[5]) != 0)
408                 return (1);
409         
410         printf(
411 "Statistics:\n"
412 "- glyph_total:                 %5u\n"
413 "- glyph_normal:                %5u\n"
414 "- glyph_normal_right:          %5u\n"
415 "- glyph_bold:                  %5u\n"
416 "- glyph_bold_right:            %5u\n"
417 "- glyph_unique:                %5u\n"
418 "- glyph_dupe:                  %5u\n"
419 "- mapping_total:               %5u\n"
420 "- mapping_normal:              %5u\n"
421 "- mapping_normal_folded:       %5u\n"
422 "- mapping_normal_right:        %5u\n"
423 "- mapping_normal_right_folded: %5u\n"
424 "- mapping_bold:                %5u\n"
425 "- mapping_bold_folded:         %5u\n"
426 "- mapping_bold_right:          %5u\n"
427 "- mapping_bold_right_folded:   %5u\n"
428 "- mapping_unique:              %5u\n"
429 "- mapping_dupe:                %5u\n",
430             glyph_total,
431             glyph_count[0],
432             glyph_count[1],
433             glyph_count[2],
434             glyph_count[3],
435             glyph_unique, glyph_dupe,
436             mapping_total,
437             map_count[0], map_folded_count[0],
438             map_count[1], map_folded_count[1],
439             map_count[2], map_folded_count[2],
440             map_count[3], map_folded_count[3],
441             mapping_unique, mapping_dupe);
442         
443         return (0);
444 }