richedit: Correctly set the pitch and family for a font when reading an RTF stream.
[wine.git] / tools / sfnt2fnt.c
blob0a32598ab0120e8527adff29859e5dbc09408e3b
1 /*
2 * sfnttofnt. Bitmap only ttf to Window fnt file converter
4 * Copyright 2004 Huw Davies
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <assert.h>
25 #include <ctype.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <stdlib.h>
30 #ifdef HAVE_FREETYPE
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
43 #include "wine/unicode.h"
44 #include "wine/wingdi16.h"
45 #include "wingdi.h"
47 #include "pshpack1.h"
49 typedef struct
51 WORD dfVersion;
52 DWORD dfSize;
53 char dfCopyright[60];
54 } FNT_HEADER;
56 typedef struct {
57 WORD width;
58 DWORD offset;
59 } CHAR_TABLE_ENTRY;
61 typedef struct {
62 DWORD version;
63 ULONG numSizes;
64 } eblcHeader_t;
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;
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;
96 typedef struct
98 FT_Int major;
99 FT_Int minor;
100 FT_Int patch;
101 } FT_Version_t;
102 static FT_Version_t FT_Version;
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]) ))
108 #include "poppack.h"
110 static const char *output_name;
112 static void usage(char **argv)
114 fprintf(stderr, "%s foo.ttf ppem enc dpi def_char avg_width\n", argv[0]);
115 return;
118 #ifndef __GNUC__
119 #define __attribute__(X)
120 #endif
122 /* atexit handler to cleanup files */
123 static void cleanup(void)
125 if (output_name) unlink( output_name );
128 static void exit_on_signal( int sig )
130 exit(1); /* this will call the atexit functions */
133 static void error(const char *s, ...) __attribute__((format (printf, 1, 2)));
135 static void error(const char *s, ...)
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);
145 static int lookup_charset(int enc)
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;
194 fprintf(stderr, "Unknown encoding %d - using OEM_CHARSET\n", enc);
196 return OEM_CHARSET;
199 static int get_char(const union cptable *cptable, int enc, int index)
201 /* Korean has the Won sign in place of '\\' */
202 if(enc == 949 && index == '\\')
203 return 0x20a9;
205 return cptable->sbcs.cp2uni[index];
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)
212 FT_Error err;
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)
222 /* 2.0.x */
223 sfnt = *(SFNT_Interface**)((char*)tt_face + 528);
225 else
227 /* A field was added in the middle of the structure in 2.1.x */
228 sfnt = *(SFNT_Interface**)((char*)tt_face + 532);
230 err = sfnt->load_any(tt_face, table, offset, buf, len);
231 #else
232 err = FT_Err_Unimplemented_Feature;
233 #endif
234 return err;
237 static void fill_fontinfo(FT_Face face, int enc, FILE *fp, int dpi, unsigned char def_char, int avg_width)
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;
256 cptable = wine_cp_get_table(enc);
257 if(!cptable)
258 error("Can't find codepage %d\n", enc);
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");
267 ppem = face->size->metrics.y_ppem;
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
274 eblc = malloc(needed);
275 load_sfnt_table(face, TTAG_EBLC, 0, (FT_Byte *)eblc, &needed);
277 num_sizes = GET_BE_DWORD(&eblc->numSizes);
279 size_table = (bitmapSizeTable_t *)(eblc + 1);
280 for(i = 0; i < num_sizes; i++)
282 if(size_table->hori.ascender - size_table->hori.descender == ppem)
284 ascent = size_table->hori.ascender;
285 descent = -size_table->hori.descender;
286 break;
288 size_table++;
291 free(eblc);
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)
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;
306 start = sizeof(FNT_HEADER) + sizeof(FONTINFO16);
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);
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;
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 */
326 dfCharTable = malloc((255 + 3) * sizeof(*dfCharTable));
327 memset(dfCharTable, 0, (255 + 3) * sizeof(*dfCharTable));
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);
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;
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;
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;
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);
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;
408 break;
409 default:
410 fi.dfPitchAndFamily |= FF_DONTCARE;
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;
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 */
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);
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;
435 assert(dfCharTable[i].width == face->glyph->metrics.horiAdvance >> 6);
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;
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;
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];
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];
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);
467 for(x = 0; x < (space_size + 7) / 8; x++) {
468 for(y = 0; y < ppem; y++)
469 fputc('\0', fp);
472 if(width_bytes & 1) {
473 for(y = 0; y < ppem; y++)
474 fputc('\0', fp);
476 fprintf(fp, "%s", face->family_name);
477 fputc('\0', fp);
482 int main(int argc, char **argv)
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);
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]);
504 if(FT_Init_FreeType(&lib))
505 error("ft init failure\n");
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);
510 if(FT_New_Face(lib, argv[1], 0, &face)) {
511 fprintf(stderr, "Can't open face\n");
512 usage(argv);
513 exit(1);
516 if(FT_Set_Pixel_Sizes(face, ppem, ppem)) {
517 fprintf(stderr, "Can't set size\n");
518 usage(argv);
519 exit(1);
522 strcpy(name, face->family_name);
523 /* FIXME: should add a -o option instead */
524 for(cp = name; *cp; cp++)
526 if(*cp == ' ') *cp = '_';
527 else if (*cp >= 'A' && *cp <= 'Z') *cp += 'a' - 'A';
530 sprintf(output, "%s-%d-%d-%d.fnt", name, enc, dpi, ppem);
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
539 fp = fopen(output, "w");
540 output_name = output;
542 fill_fontinfo(face, enc, fp, dpi, def_char, avg_width);
543 fclose(fp);
544 output_name = NULL;
545 exit(0);
548 #else /* HAVE_FREETYPE */
550 int main(int argc, char **argv)
552 fprintf( stderr, "%s needs to be built with FreeType support\n", argv[0] );
553 exit(1);
556 #endif /* HAVE_FREETYPE */