comctl32: A couple fixes for tab icon offsets.
[wine] / tools / sfnt2fnt.c
1 /*
2  * sfnttofnt.  Bitmap only ttf to Window fnt file converter
3  *
4  * Copyright 2004 Huw Davies
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <assert.h>
25 #include <ctype.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28
29 #ifdef HAVE_FREETYPE
30
31 #ifdef HAVE_FT2BUILD_H
32 #include <ft2build.h>
33 #endif
34 #include FT_FREETYPE_H
35 #include FT_SFNT_NAMES_H
36 #include FT_TRUETYPE_TABLES_H
37 #include FT_TRUETYPE_TAGS_H
38
39 #include "wine/unicode.h"
40 #include "wine/wingdi16.h"
41 #include "wingdi.h"
42
43 #include "pshpack1.h"
44
45 typedef struct
46 {
47     WORD dfVersion;
48     DWORD dfSize;
49     char dfCopyright[60];
50 } FNT_HEADER;
51
52 typedef struct {
53     WORD width;
54     DWORD offset;
55 } CHAR_TABLE_ENTRY;
56
57 typedef struct {
58     DWORD version;
59     ULONG numSizes;
60 } eblcHeader_t;
61
62 typedef struct {
63     CHAR ascender;
64     CHAR descender;
65     BYTE widthMax;
66     CHAR caretSlopeNumerator;
67     CHAR caretSlopeDenominator;
68     CHAR caretOffset;
69     CHAR minOriginSB;
70     CHAR minAdvanceSB;
71     CHAR maxBeforeBL;
72     CHAR maxAfterBL;
73     CHAR pad1;
74     CHAR pad2;
75 } sbitLineMetrics_t;
76
77 typedef struct {
78     ULONG indexSubTableArrayOffset;
79     ULONG indexTableSize;
80     ULONG numberOfIndexSubTables;
81     ULONG colorRef;
82     sbitLineMetrics_t hori;
83     sbitLineMetrics_t vert;
84     USHORT startGlyphIndex;
85     USHORT endGlyphIndex;
86     BYTE ppemX;
87     BYTE ppemY;
88     BYTE bitDepth;
89     CHAR flags;
90 } bitmapSizeTable_t;
91
92 #define GET_BE_WORD(ptr)  MAKEWORD( ((BYTE *)(ptr))[1], ((BYTE *)(ptr))[0] )
93 #define GET_BE_DWORD(ptr) ((DWORD)MAKELONG( GET_BE_WORD(&((WORD *)(ptr))[1]), \
94                                             GET_BE_WORD(&((WORD *)(ptr))[0]) ))
95
96 #include "poppack.h"
97
98 static const char *output_name;
99
100 static void usage(char **argv)
101 {
102     fprintf(stderr, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv[0]);
103     return;
104 }
105
106 #ifndef __GNUC__
107 #define __attribute__(X)
108 #endif
109
110 /* atexit handler to cleanup files */
111 static void cleanup(void)
112 {
113     if (output_name) unlink( output_name );
114 }
115
116 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
117
118 static void error(const char *s, ...)
119 {
120     va_list ap;
121     va_start(ap, s);
122     fprintf(stderr, "Error: ");
123     vfprintf(stderr, s, ap);
124     va_end(ap);
125     exit(1);
126 }
127
128 static int lookup_charset(int enc)
129 {
130     /* FIXME: make winelib app and use TranslateCharsetInfo */
131     switch(enc) {
132     case 1250:
133         return EE_CHARSET;
134     case 1251:
135         return RUSSIAN_CHARSET;
136     case 1252:
137         return ANSI_CHARSET;
138     case 1253:
139         return GREEK_CHARSET;
140     case 1254:
141         return TURKISH_CHARSET;
142     case 1255:
143         return HEBREW_CHARSET;
144     case 1256:
145         return ARABIC_CHARSET;
146     case 1257:
147         return BALTIC_CHARSET;
148     case 1258:
149         return VIETNAMESE_CHARSET;
150     case 437:
151     case 737:
152     case 775:
153     case 850:
154     case 852:
155     case 855:
156     case 857:
157     case 860:
158     case 861:
159     case 862:
160     case 863:
161     case 864:
162     case 865:
163     case 866:
164     case 869:
165         return OEM_CHARSET;
166     case 874:
167         return THAI_CHARSET;
168     case 932:
169         return SHIFTJIS_CHARSET;
170     case 936:
171         return GB2312_CHARSET;
172     case 949:
173         return HANGUL_CHARSET;
174     case 950:
175         return CHINESEBIG5_CHARSET;
176     }
177     fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
178
179     return OEM_CHARSET;
180 }
181
182 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
183 {
184     int ascent = 0, il, ppem, descent = 0, width_bytes = 0, space_size, max_width = 0;
185     FNT_HEADER hdr;
186     FONTINFO16 fi;
187     BYTE left_byte, right_byte, byte;
188     DWORD start;
189     CHAR_TABLE_ENTRY *dfCharTable;
190     int i, x, y, x_off, x_end, first_char;
191     FT_UInt gi;
192     int num_names;
193     const union cptable *cptable;
194     FT_SfntName sfntname;
195     TT_OS2 *os2;
196     FT_ULong needed;
197     eblcHeader_t *eblc;
198     bitmapSizeTable_t *size_table;
199     int num_sizes;
200
201     cptable = wine_cp_get_table(enc);
202     if(!cptable)
203         error("Can't find codepage %d\n", enc);
204
205     if(cptable->info.char_size != 1) {
206         /* for double byte charsets we actually want to use cp1252 */
207         cptable = wine_cp_get_table(1252);
208         if(!cptable)
209             error("Can't find codepage 1252\n");
210     }
211
212     ppem = face->size->metrics.y_ppem;
213
214     needed = 0;
215     if(FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, NULL, &needed))
216         error("Can't find EBLC table\n");
217
218     eblc = malloc(needed);
219     FT_Load_Sfnt_Table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
220
221     num_sizes = GET_BE_DWORD(&eblc->numSizes);
222
223     size_table = (bitmapSizeTable_t *)(eblc + 1);
224     for(i = 0; i < num_sizes; i++)
225     {
226         if(size_table->hori.ascender - size_table->hori.descender == ppem)
227         {
228             ascent = size_table->hori.ascender;
229             descent = -size_table->hori.descender;
230             break;
231         }
232         size_table++;
233     }
234
235     /* Versions of fontforge prior to early 2006 have incorrect
236        ascender values in the eblc table, so we won't find the 
237        correct bitmapSizeTable.  In this case use the height of
238        the Aring glyph instead. */
239     if(ascent == 0) 
240     {
241         if(FT_Load_Char(face, 0xc5, FT_LOAD_DEFAULT))
242             error("Can't find Aring\n");
243         ascent = face->glyph->metrics.horiBearingY >> 6;
244         descent = ppem - ascent;
245     }
246
247     free(eblc);
248
249     start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
250
251     if(FT_Load_Char(face, 'M', FT_LOAD_DEFAULT))
252         error("Can't find M\n");
253     il = ascent - (face->glyph->metrics.height >> 6);
254
255     /* Hack: Courier has no internal leading, nor do any Chinese fonts */
256     if(!strcmp(face->family_name, "Courier") || enc == 936 || enc == 950)
257         il = 0;
258
259     first_char = FT_Get_First_Char(face, &gi);
260     if(first_char == 0xd) /* fontforge's first glyph is 0xd, we'll catch this and skip it */
261         first_char = 32; /* FT_Get_Next_Char for some reason returns too high
262                             number in this case */
263
264     dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
265     memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
266
267     memset(&fi, 0, sizeof(fi));
268     fi.dfFirstChar = first_char;
269     fi.dfLastChar = 0xff;
270     start += ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar + 3 ) * sizeof(*dfCharTable);
271
272     num_names = FT_Get_Sfnt_Name_Count(face);
273     for(i = 0; i <num_names; i++) {
274         FT_Get_Sfnt_Name(face, i, &sfntname);
275         if(sfntname.platform_id == 1 && sfntname.encoding_id == 0 &&
276            sfntname.language_id == 0 && sfntname.name_id == 0) {
277             size_t len = min( sfntname.string_len, sizeof(hdr.dfCopyright)-1 );
278             memcpy(hdr.dfCopyright, sfntname.string, len);
279             hdr.dfCopyright[len] = 0;
280         }
281     }
282
283     os2 = FT_Get_Sfnt_Table(face, ft_sfnt_os2);
284     for(i = first_char; i < 0x100; i++) {
285         gi = FT_Get_Char_Index(face, cptable->sbcs.cp2uni[i]);
286         if(gi == 0)
287             fprintf(stderr, "Missing glyph for char %04x\n", cptable->sbcs.cp2uni[i]);
288         if(FT_Load_Char(face, cptable->sbcs.cp2uni[i], FT_LOAD_DEFAULT)) {
289             fprintf(stderr, "error loading char %d - bad news!\n", i);
290             continue;
291         }
292         dfCharTable[i].width = face->glyph->metrics.horiAdvance >> 6;
293         dfCharTable[i].offset = start + (width_bytes * ppem);
294         width_bytes += ((face->glyph->metrics.horiAdvance >> 6) + 7) >> 3;
295         if(max_width < (face->glyph->metrics.horiAdvance >> 6))
296             max_width = face->glyph->metrics.horiAdvance >> 6;
297     }
298     /* space */
299     space_size = (ppem + 3) / 4;
300     dfCharTable[i].width = space_size;
301     dfCharTable[i].offset = start + (width_bytes * ppem);
302     width_bytes += (space_size + 7) >> 3;
303     /* sentinel */
304     dfCharTable[++i].width = 0;
305     dfCharTable[i].offset = start + (width_bytes * ppem);
306
307     fi.dfType = 0;
308     fi.dfPoints = ((ppem - il) * 72 + dpi/2) / dpi;
309     fi.dfVertRes = dpi;
310     fi.dfHorizRes = dpi;
311     fi.dfAscent = ascent;
312     fi.dfInternalLeading = il;
313     fi.dfExternalLeading = 0;
314     fi.dfItalic = (face->style_flags & FT_STYLE_FLAG_ITALIC) ? 1 : 0;
315     fi.dfUnderline = 0;
316     fi.dfStrikeOut = 0;
317     fi.dfWeight = os2->usWeightClass;
318     fi.dfCharSet = lookup_charset(enc);
319     fi.dfPixWidth = (face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) ?
320         avg_width : 0;
321     fi.dfPixHeight = ppem;
322     fi.dfPitchAndFamily = FT_IS_FIXED_WIDTH(face) ? 0 : TMPF_FIXED_PITCH;
323     switch(os2->panose[PAN_FAMILYTYPE_INDEX]) {
324     case PAN_FAMILY_SCRIPT:
325         fi.dfPitchAndFamily |= FF_SCRIPT;
326         break;
327     case PAN_FAMILY_DECORATIVE:
328     case PAN_FAMILY_PICTORIAL:
329         fi.dfPitchAndFamily |= FF_DECORATIVE;
330         break;
331     case PAN_FAMILY_TEXT_DISPLAY:
332         if(fi.dfPitchAndFamily == 0) /* fixed */
333             fi.dfPitchAndFamily = FF_MODERN;
334         else {
335             switch(os2->panose[PAN_SERIFSTYLE_INDEX]) {
336             case PAN_SERIF_NORMAL_SANS:
337             case PAN_SERIF_OBTUSE_SANS:
338             case PAN_SERIF_PERP_SANS:
339                 fi.dfPitchAndFamily |= FF_SWISS;
340                 break;
341             default:
342                 fi.dfPitchAndFamily |= FF_ROMAN;
343             }
344         }
345         break;
346     default:
347         fi.dfPitchAndFamily |= FF_DONTCARE;
348     }
349
350     fi.dfAvgWidth = avg_width;
351     fi.dfMaxWidth = max_width;
352     fi.dfDefaultChar = def_char - fi.dfFirstChar;
353     fi.dfBreakChar = ' ' - fi.dfFirstChar;
354     fi.dfWidthBytes = (width_bytes + 1) & ~1;
355
356     fi.dfFace = start + fi.dfWidthBytes * ppem;
357     fi.dfBitsOffset = start;
358     fi.dfFlags = 0x10; /* DFF_1COLOR */
359     fi.dfFlags |= FT_IS_FIXED_WIDTH(face) ? 1 : 2; /* DFF_FIXED : DFF_PROPORTIONAL */
360
361     hdr.dfVersion = 0x300;
362     hdr.dfSize = start + fi.dfWidthBytes * ppem + strlen(face->family_name) + 1;
363     fwrite(&hdr, sizeof(hdr), 1, fp);
364     fwrite(&fi, sizeof(fi), 1, fp);
365     fwrite(dfCharTable + fi.dfFirstChar, sizeof(*dfCharTable), ((unsigned char)fi.dfLastChar - (unsigned char)fi.dfFirstChar) + 3, fp);
366
367     for(i = first_char; i < 0x100; i++) {
368         if(FT_Load_Char(face, cptable->sbcs.cp2uni[i], FT_LOAD_DEFAULT)) {
369             continue;
370         }
371         assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
372
373         for(x = 0; x < ((dfCharTable[i].width + 7) / 8); x++) {
374             for(y = 0; y < ppem; y++) {
375                 if(y < ascent - face->glyph->bitmap_top ||
376                    y >=  face->glyph->bitmap.rows + ascent - face->glyph->bitmap_top) {
377                     fputc('\0', fp);
378                     continue;
379                 }
380                 x_off = face->glyph->bitmap_left / 8;
381                 x_end = (face->glyph->bitmap_left + face->glyph->bitmap.width - 1) / 8;
382                 if(x < x_off || x > x_end) {
383                     fputc('\0', fp);
384                     continue;
385                 }
386                 if(x == x_off)
387                     left_byte = 0;
388                 else
389                     left_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off - 1];
390
391                 /* On the last non-trival output byte (x == x_end) have we got one or two input bytes */
392                 if(x == x_end && (face->glyph->bitmap_left % 8 != 0) && ((face->glyph->bitmap.width % 8 == 0) || (x != (((face->glyph->bitmap.width) & ~0x7) + face->glyph->bitmap_left) / 8)))
393                     right_byte = 0;
394                 else
395                     right_byte = face->glyph->bitmap.buffer[(y - (ascent - face->glyph->bitmap_top)) * face->glyph->bitmap.pitch + x - x_off];
396
397                 byte = (left_byte << (8 - (face->glyph->bitmap_left & 7))) & 0xff;
398                 byte |= ((right_byte >> (face->glyph->bitmap_left & 7)) & 0xff);
399                 fputc(byte, fp);
400             }
401         }
402     }
403     for(x = 0; x < (space_size + 7) / 8; x++) {
404         for(y = 0; y < ppem; y++)
405             fputc('\0', fp);
406     }
407
408     if(width_bytes & 1) {
409         for(y = 0; y < ppem; y++)
410             fputc('\0', fp);
411     }
412     fprintf(fp, "%s", face->family_name);
413     fputc('\0', fp);
414
415 }
416
417
418 int main(int argc, char **argv)
419 {
420     int ppem, enc;
421     FT_Face face;
422     FT_Library lib;
423     int dpi, avg_width;
424     unsigned int def_char;
425     FILE *fp;
426     char output[256];
427     char name[256];
428     char *cp;
429     if(argc != 7) {
430         usage(argv);
431         exit(0);
432     }
433
434     ppem = atoi(argv[2]);
435     enc = atoi(argv[3]);
436     dpi = atoi(argv[4]);
437     def_char = atoi(argv[5]);
438     avg_width = atoi(argv[6]);
439
440     if(FT_Init_FreeType(&lib))
441         error("ft init failure\n");
442
443     if(FT_New_Face(lib, argv[1], 0, &face)) {
444         fprintf(stderr, "Can't open face\n");
445         usage(argv);
446         exit(1);
447     }
448
449     if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
450         fprintf(stderr, "Can't set size\n");
451         usage(argv);
452         exit(1);
453     }
454
455     strcpy(name, face->family_name);
456     /* FIXME: should add a -o option instead */
457     for(cp = name; *cp; cp++)
458     {
459         if(*cp == ' ') *cp = '_';
460         else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
461     }
462
463     sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
464
465     atexit( cleanup );
466     fp = fopen(output, "w");
467     output_name = output;
468
469     fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
470     fclose(fp);
471     output_name = NULL;
472     exit(0);
473 }
474
475 #else /* HAVE_FREETYPE */
476
477 int main(int argc, char **argv)
478 {
479     fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
480     exit(1);
481 }
482
483 #endif /* HAVE_FREETYPE */