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