diff options
author | John Mark Bell <jmb@netsurf-browser.org> | 2009-05-07 15:22:02 +0000 |
---|---|---|
committer | John Mark Bell <jmb@netsurf-browser.org> | 2009-05-07 15:22:02 +0000 |
commit | a98d8fb5e49436c6fedea37797225293284b9894 (patch) | |
tree | f140662044f20668b937c9f3b451c56345678108 /src | |
download | ttf2f-a98d8fb5e49436c6fedea37797225293284b9894.tar.gz ttf2f-a98d8fb5e49436c6fedea37797225293284b9894.tar.bz2 |
Import TTF2f. Don't expect this to link; I've prevented it building main.c.
svn path=/trunk/tools/ttf2f/; revision=7427
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/encoding.c | 71 | ||||
-rw-r--r-- | src/encoding.h | 11 | ||||
-rw-r--r-- | src/fm.h | 31 | ||||
-rw-r--r-- | src/ft.c | 569 | ||||
-rw-r--r-- | src/ft.h | 20 | ||||
-rw-r--r-- | src/glyph.h | 39 | ||||
-rw-r--r-- | src/glyphs.c | 101 | ||||
-rw-r--r-- | src/glyphs.h | 8 | ||||
-rw-r--r-- | src/intmetrics.c | 154 | ||||
-rw-r--r-- | src/intmetrics.h | 12 | ||||
-rw-r--r-- | src/main.c | 456 | ||||
-rw-r--r-- | src/outlines.c | 297 | ||||
-rw-r--r-- | src/outlines.h | 58 | ||||
-rw-r--r-- | src/utils.c | 39 | ||||
-rw-r--r-- | src/utils.h | 12 |
16 files changed, 1882 insertions, 0 deletions
diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..4f16a84 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,4 @@ +# Sources +DIR_SOURCES := encoding.c ft.c glyphs.c intmetrics.c outlines.c utils.c + +include build/makefiles/Makefile.subdir diff --git a/src/encoding.c b/src/encoding.c new file mode 100644 index 0000000..4d5bcde --- /dev/null +++ b/src/encoding.c @@ -0,0 +1,71 @@ +#include <stdio.h> +#include <string.h> + +#include "encoding.h" +#include "fm.h" +#include "glyph.h" +#include "utils.h" + +/** + * Write font encoding file (UCS style sparse encoding) + * + * \param savein Location to save in + * \param name The font name + * \param glyph_list List of all glyphs in the font + * \param list_size Size of glyph list + * \param type File format to use - 0 = full; 1 = sparse + * \param callback Progress callback function + */ +void write_encoding(const char *savein, const char *name, + struct glyph *glyph_list, int list_size, int type, + void (*callback)(int progress)) +{ + FILE *output; + struct glyph *g; + int i; + char out[1024]; + + snprintf(out, 1024, "%s.Encoding", savein); + output = fopen(out, "w+"); + + fprintf(output, "%% %sEncoding 1.00\n", name); + fprintf(output, "%% Encoding file for font '%s'\n\n", name); + + if (!type) { + for (i = 0; i != 32; i++) { + fprintf(output, "/.notdef\n"); + } + } + + for (i = 0; i != list_size; i++) { + g = &glyph_list[i]; + + callback(i * 100 / list_size); + ttf2f_poll(1); + + if (type) { + if (g->name != 0) { + /* .notdef is implicit */ + if (strcmp(g->name, ".notdef") == 0) + continue; + fprintf(output, "%4.4X;%s;COMMENT\n", i+32, + g->name); + } else if (g->code != (unsigned int) -1) + fprintf(output, "%4.4X;uni%04X;COMMENT\n", + i+32, g->code); + else + fprintf(output, "# Skipping %4.4X\n", i+32); + } + else { + if (g->name != 0) { + fprintf(output, "/%s\n", g->name); + } else if (g->code != (unsigned int) -1) + fprintf(output, "/uni%4.4X\n", g->code); + else + fprintf(output, "/.NotDef\n"); + } + } + + fclose(output); +} + diff --git a/src/encoding.h b/src/encoding.h new file mode 100644 index 0000000..3a88cad --- /dev/null +++ b/src/encoding.h @@ -0,0 +1,11 @@ +#ifndef _TTF2F_ENCODING_H_ +#define _TTF2F_ENCODING_H_ + +struct glyph; + +void write_encoding(const char *savein, const char *name, + struct glyph *glyph_list, int list_size, int type, + void (*callback)(int progress)); + +#endif + diff --git a/src/fm.h b/src/fm.h new file mode 100644 index 0000000..f8e024e --- /dev/null +++ b/src/fm.h @@ -0,0 +1,31 @@ +#ifndef _TTF2F_FM_H_ +#define _TTF2F_FM_H_ + +struct font_metrics { + /* post */ + double italic_angle; + short underline_position; + short underline_thickness; + short is_fixed_pitch; + + /* hhea */ + short ascender; + short descender; + + /* head */ + unsigned short units_per_em; + short bbox[4]; + + /* name */ + char *name_copyright; + char *name_family; + char *name_style; + char *name_full; + char *name_version; + char *name_ps; + + /* other */ + int force_bold; +}; + +#endif diff --git a/src/ft.c b/src/ft.c new file mode 100644 index 0000000..b8f548b --- /dev/null +++ b/src/ft.c @@ -0,0 +1,569 @@ +/* + * The font parser using the FreeType library version 2. + * + * based in part upon the ft.c source file in TTF2PT1 + * + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include "ft2build.h" +#include FT_FREETYPE_H +#include "freetype/freetype.h" +#include "freetype/ftglyph.h" +#include "freetype/ftsnames.h" +#include "freetype/ttnameid.h" +#include "freetype/ftoutln.h" +#include "freetype/tttables.h" + +#include "ft.h" +#include "fm.h" +#include "glyph.h" +#include "glyphs.h" +#include "utils.h" + +/* statics */ + +static FT_Library library; +static FT_Face face; + +void ft_init(void) +{ + if (FT_Init_FreeType(&library)) { + fprintf(stderr, "** FreeType initialization failed\n"); + exit(1); + } +} + +void ft_fini(void) +{ + if (face) + close_font(); + + if (FT_Done_FreeType(library)) { + fprintf(stderr, "Errors when stopping FreeType, ignored\n"); + } +} + +/* + * Open font and prepare to return information to the main driver. + * May print error and warning messages. + */ + +int open_font(char *fname) +{ + FT_Error error; + + if ((error = FT_New_Face(library, fname, 0, &face)) != 0) { + if (error == FT_Err_Unknown_File_Format) + fprintf(stderr, "**** %s has format unknown to FreeType\n", fname); + else + fprintf(stderr, "**** Cannot access %s ****\n", fname); + return 1; + } + + return 0; +} + +/* + * Close font. + * Exit on error. + */ + +void close_font(void) +{ + if (FT_Done_Face(face)) { + fprintf(stderr, "Errors when closing the font file, ignored\n"); + } + + face = 0; +} + +/* + * Get the number of glyphs in font. + */ + +int count_glyphs(void) +{ + return (int)face->num_glyphs; +} + +/* + * Get the names of the glyphs. + * Returns 0 if the names were assigned, non-zero on error + */ + +int glnames(struct glyph *glyph_list) +{ +#define MAX_NAMELEN 1024 +// unsigned char bf[1024]; + int i; + +// if (!FT_HAS_GLYPH_NAMES(face)) { +// fprintf(stderr, "Font has no glyph names\n"); +// return 0; +// } + +// for (i = 0; i < face->num_glyphs; i++) { +// if (FT_Get_Glyph_Name(face, i, bf, MAX_NAMELEN) || bf[0]==0) { +// sprintf((char*)bf, "_g_%d", i); +// fprintf(stderr, +// "Glyph No. %d has no postscript name, becomes %s\n", i, bf); +// } + +// /* don't copy .notdef across when not necessary */ +// if (i == 0 || strcmp((char*)bf, ".notdef") != 0) { +// glyph_list[i].name = strdup((char*)bf); + +// if (glyph_list[i].name == NULL) { +// fprintf (stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); +// return 1; +// } +// } +// } + + for (i = 0; i != face->num_glyphs; i++) { + ttf2f_poll(1); + glyph_list[i].name = glyph_name(glyph_list[i].code); + } + + return 0; +} + +/* + * Get the metrics of the glyphs. + */ + +void glmetrics(struct glyph *glyph_list, void (*callback)(int progress)) +{ + struct glyph *g; + int i; + FT_Glyph_Metrics *met; + FT_BBox bbox; + FT_Glyph gly; + + for (i = 0; i < face->num_glyphs; i++) { + g = &(glyph_list[i]); + + callback(i * 100 / face->num_glyphs); + ttf2f_poll(1); + + if (FT_Load_Glyph(face, i, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE)) { + fprintf(stderr, "Can't load glyph %s, skipped\n", g->name); + continue; + } + + met = &face->glyph->metrics; + + if (FT_HAS_HORIZONTAL(face)) { + g->width = convert_units(met->horiAdvance, + face->units_per_EM); + g->lsb = convert_units(met->horiBearingX, + face->units_per_EM); + } else { + fprintf(stderr, "Glyph %s has no horizontal metrics, guessed them\n", g->name); + g->width = convert_units(met->width, + face->units_per_EM); + g->lsb = 0; + } + + if (FT_Get_Glyph(face->glyph, &gly)) { + fprintf(stderr, "Can't access glyph %s bbox, skipped\n", g->name); + continue; + } + + FT_Glyph_Get_CBox(gly, ft_glyph_bbox_unscaled, &bbox); + g->xMin = convert_units(bbox.xMin, face->units_per_EM); + g->yMin = convert_units(bbox.yMin, face->units_per_EM); + g->xMax = convert_units(bbox.xMax, face->units_per_EM); + g->yMax = convert_units(bbox.yMax, face->units_per_EM); + + g->ttf_pathlen = face->glyph->outline.n_points; + + FT_Done_Glyph(gly); + } +} + +/* + * Map charcodes to glyph ids using the unicode encoding + */ + +int glenc(struct glyph *glyph_list) +{ + unsigned charcode, glyphid; + + if (!face->charmaps || FT_Select_Charmap(face, FT_ENCODING_UNICODE)) { + fprintf(stderr, "**** Cannot set charmap in FreeType ****\n"); + return 1; + } + + charcode = FT_Get_First_Char(face, &glyphid); + while (glyphid != 0) { + ttf2f_poll(1); + glyph_list[glyphid].code = charcode; + charcode = FT_Get_Next_Char(face, charcode, &glyphid); + } + + return 0; +} + +/* + * Get the font metrics + */ +int fnmetrics(struct font_metrics *fm) +{ + char *str; + static char *fieldstocheck[3]; + FT_SfntName sn; + TT_Postscript *post; + int i, j, len; + + fm->underline_position = convert_units(face->underline_position, + face->units_per_EM); + fm->underline_thickness = convert_units(face->underline_thickness, + face->units_per_EM); + fm->is_fixed_pitch = FT_IS_FIXED_WIDTH(face); + + fm->ascender = convert_units(face->ascender, face->units_per_EM); + fm->descender = convert_units(face->descender, face->units_per_EM); + + fm->units_per_em = face->units_per_EM; + + fm->bbox[0] = convert_units(face->bbox.xMin, face->units_per_EM); + fm->bbox[1] = convert_units(face->bbox.yMin, face->units_per_EM); + fm->bbox[2] = convert_units(face->bbox.xMax, face->units_per_EM); + fm->bbox[3] = convert_units(face->bbox.yMax, face->units_per_EM); + + if ((post = (TT_Postscript*)FT_Get_Sfnt_Table(face, ft_sfnt_post)) != NULL) + fm->italic_angle = post->italicAngle; + else { + fprintf(stderr, "hidden"); + fm->italic_angle = 0.0; /* FreeType hides the angle */ + } + + if (FT_Get_Sfnt_Name(face, TT_NAME_ID_COPYRIGHT, &sn)) + fm->name_copyright = (char *) ""; + else + fm->name_copyright = strndup((const char*)sn.string, sn.string_len); + + fm->name_family = face->family_name; + + fm->name_style = face->style_name; + if (fm->name_style == NULL) + fm->name_style = (char *) ""; + + if (FT_Get_Sfnt_Name(face, TT_NAME_ID_FULL_NAME, &sn)) { + int len; + + len = strlen(fm->name_family) + strlen(fm->name_style) + 2; + if ((fm->name_full = malloc(len)) == NULL) { + fprintf(stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); + return 1; + } + strcpy(fm->name_full, fm->name_family); + if (strlen(fm->name_style) != 0) { + strcat(fm->name_full, " "); + strcat(fm->name_full, fm->name_style); + } + } + else + fm->name_full = strndup((const char*)sn.string, sn.string_len); + + if (FT_Get_Sfnt_Name(face, TT_NAME_ID_VERSION_STRING, &sn)) + fm->name_version = (char *) "1.0"; + else + fm->name_version = strndup((const char*)sn.string, sn.string_len); + + if (FT_Get_Sfnt_Name(face, TT_NAME_ID_PS_NAME , &sn)) { + if ((fm->name_ps = strdup(fm->name_full)) == NULL) { + fprintf(stderr, "****malloc failed %s line %d\n", __FILE__, __LINE__); + return 1; + } + } else + fm->name_ps = strndup((const char*)sn.string, sn.string_len); + for (i = 0; fm->name_ps[i]!=0; i++) + if (fm->name_ps[i] == ' ') + fm->name_ps[i] = '_'; /* no spaces in the Postscript name */ + + /* guess the boldness from the font names */ + fm->force_bold=0; + + fieldstocheck[0] = fm->name_style; + fieldstocheck[1] = fm->name_full; + fieldstocheck[2] = fm->name_ps; + + for (i = 0; !fm->force_bold && i < (int) (sizeof fieldstocheck / sizeof(fieldstocheck[0])); i++) { + str=fieldstocheck[i]; + len = strlen(str); + for (j = 0; j < len; j++) { + if ((str[j]=='B' + || str[j]=='b') + && (j==0 || !isalpha(str[j-1])) + && !strncmp("old",&str[j+1],3) + && (j+4 >= len || !islower(str[j+4]))) { + fm->force_bold=1; + break; + } + } + } + + return 0; +} + +/* + * Functions to decompose the outlines + */ + +static struct glyph *curg; +static struct outline *cur_outline_entry; +static long lastx, lasty; + +static int outl_moveto(const FT_Vector *to, void *unused) +{ + struct outline *o; + + UNUSED(unused); + + o = calloc(1, sizeof(struct outline)); + if (!o) { + fprintf(stderr, "malloc failed\n"); + return 1; + } + + o->type = MOVE_TO; + o->data.move_to.x = convert_units(to->x, face->units_per_EM); + o->data.move_to.y = convert_units(to->y, face->units_per_EM); + + if (cur_outline_entry) + cur_outline_entry->next = o; + else + curg->outline = o; + cur_outline_entry = o; + + lastx = convert_units(to->x, face->units_per_EM); + lasty = convert_units(to->y, face->units_per_EM); + +/* fprintf(stderr, "\tmoving to: (%x, %x)(%x, %x)\n", o->data.move_to.x, o->data.move_to.y, to->x, to->y); +*/ + return 0; +} + +static int outl_lineto(const FT_Vector *to, void *unused) +{ + struct outline *o; + + UNUSED(unused); + + o = calloc(1, sizeof(struct outline)); + if (!o) { + fprintf(stderr, "malloc failed\n"); + return 1; + } + + o->type = LINE_TO; + o->data.line_to.x = convert_units(to->x, face->units_per_EM); + o->data.line_to.y = convert_units(to->y, face->units_per_EM); + + if (cur_outline_entry) + cur_outline_entry->next = o; + else + curg->outline = o; + cur_outline_entry = o; + + lastx = convert_units(to->x, face->units_per_EM); + lasty = convert_units(to->y, face->units_per_EM); + +/* fprintf(stderr, "\tdrawing line to: (%x, %x)(%x, %x)\n", o->data.line_to.x, o->data.line_to.y, to->x, to->y); +*/ + return 0; +} + +static int outl_conicto(const FT_Vector *control1, const FT_Vector *to, + void *unused) +{ + struct outline *o; + double c1x, c1y; + + UNUSED(unused); + + o = calloc(1, sizeof(struct outline)); + if (!o) { + fprintf(stderr, "malloc failed\n"); + return 1; + } + + c1x = (double)lastx + 2.0 * + ((double)convert_units(control1->x, face->units_per_EM) - + (double)lastx) / 3.0; + c1y = (double)lasty + 2.0 * + ((double)convert_units(control1->y, face->units_per_EM) - + (double)lasty) / 3.0; + + o->type = CURVE; + o->data.curve.x1 = (int)c1x; + o->data.curve.y1 = (int)c1y; + o->data.curve.x2 = (int)(c1x + + ((double)convert_units(to->x, face->units_per_EM) - + (double)lastx) / 3.0); + o->data.curve.y2 = (int)(c1y + + ((double)convert_units(to->y, face->units_per_EM) - + (double)lasty) / 3.0); + o->data.curve.x3 = convert_units(to->x, face->units_per_EM); + o->data.curve.y3 = convert_units(to->y, face->units_per_EM); + + if (cur_outline_entry) + cur_outline_entry->next = o; + else + curg->outline = o; + cur_outline_entry = o; + +/* fprintf(stderr, "\tdrawing conic curve to: (%x, %x)(%x, %x) ctrl1: (%x, %x)(%f, %f) ctrl2: (%x, %x)(%f, %f) qctrl: (%x, %x)\n", + o->data.curve.x3, o->data.curve.y3, to->x, to->y, + o->data.curve.x1, o->data.curve.y1, c1x, c1y, + o->data.curve.x2, o->data.curve.y2, + (c1x + (double)(to->x - lastx) / 3.0), + (c1y + (double)(to->y - lasty) / 3.0), + control1->x, control1->y); +*/ + lastx = convert_units(to->x, face->units_per_EM); + lasty = convert_units(to->y, face->units_per_EM); + + return 0; +} + +static int outl_cubicto(const FT_Vector *control1, const FT_Vector *control2, + const FT_Vector *to, void *unused) +{ + struct outline *o; + + UNUSED(unused); + + o = calloc(1, sizeof(struct outline)); + if (!o) { + fprintf(stderr, "malloc failed\n"); + return 1; + } + + o->type = CURVE; + o->data.curve.x1 = convert_units(control1->x, face->units_per_EM); + o->data.curve.y1 = convert_units(control1->y, face->units_per_EM); + o->data.curve.x2 = convert_units(control2->x, face->units_per_EM); + o->data.curve.y2 = convert_units(control2->y, face->units_per_EM); + o->data.curve.x3 = convert_units(to->x, face->units_per_EM); + o->data.curve.y3 = convert_units(to->y, face->units_per_EM); + + if (cur_outline_entry) + cur_outline_entry->next = o; + else + curg->outline = o; + cur_outline_entry = o; + + lastx = convert_units(to->x, face->units_per_EM); + lasty = convert_units(to->y, face->units_per_EM); + +/* fprintf(stderr, "\tdrawing cubic curve to: (%x, %x)(%x, %x) ctrl1: (%x, %x)(%x, %x) ctrl2: (%x, %x)(%x, %x)\n", o->data.curve.x3, o->data.curve.y3, to->x, to->y, o->data.curve.x1, o->data.curve.y1, control1->x, control1->y, o->data.curve.x2, o->data.curve.y2, control2->x, control2->y); +*/ + return 0; +} + +static FT_Outline_Funcs ft_outl_funcs = { + outl_moveto, + outl_lineto, + outl_conicto, + outl_cubicto, + 0, + 0 +}; + +/* + * Get the path of contrours for a glyph. + */ + +void glpath(int glyphno, struct glyph *glyf_list) +{ + FT_Outline *ol; + FT_Glyph gly; + struct outline *o; + + curg = &glyf_list[glyphno]; + cur_outline_entry = 0; + + if (FT_Load_Glyph(face, glyphno, FT_LOAD_NO_BITMAP|FT_LOAD_NO_SCALE|FT_LOAD_NO_HINTING) + || face->glyph->format != ft_glyph_format_outline) { + fprintf(stderr, "Can't load glyph %s, skipped\n", curg->name); + return; + } + + ol = &face->glyph->outline; + lastx = 0; lasty = 0; + +/* fprintf(stderr, "Decomposing outline of %s (%d):\n", curg->name, + glyphno); +*/ + if (FT_Outline_Decompose(ol, &ft_outl_funcs, NULL)) { + fprintf(stderr, "Can't decompose outline of glyph %s, skipped\n", curg->name); + return; + } + + o = calloc(1, sizeof(struct outline)); + if (!o) { + fprintf(stderr, "malloc failed\n"); + return; + } + + o->type = TERMINATE; + /* todo - handle composite glyphs */ + o->data.terminate.composite = 0; + + if (cur_outline_entry) + cur_outline_entry->next = o; + else + curg->outline = o; + cur_outline_entry = o; + + if (FT_Get_Glyph(face->glyph, &gly)) { + fprintf(stderr, "Can't access glyph %s bbox, skipped\n", curg->name); + return; + } + + FT_Done_Glyph(gly); + +// fprintf(stderr, "done\n\n"); +} + +#if 0 +/* + * Get the kerning data. + */ + +void kerning(struct glyph *glyph_list) +{ + int i, j, n; + int nglyphs = face->num_glyphs; + FT_Vector k; + struct glyph *gl; + + if (nglyphs == 0 || !FT_HAS_KERNING(face)) { + fputs("No Kerning data\n", stderr); + return; + } + + for (i = 0; i < nglyphs; i++) { + if ((glyph_list[i].flags & GF_USED) == 0) + continue; + for (j = 0; j < nglyphs; j++) { + if ((glyph_list[j].flags & GF_USED) == 0) + continue; + if (FT_Get_Kerning(face, i, j, ft_kerning_unscaled, &k)) + continue; + if (k.x == 0) + continue; + + addkernpair(i, j, k.x); + } + } +} + +#endif diff --git a/src/ft.h b/src/ft.h new file mode 100644 index 0000000..eb9c9ad --- /dev/null +++ b/src/ft.h @@ -0,0 +1,20 @@ +#ifndef _TTF2F_FT_H_ +#define _TTF2F_FT_H_ + +struct font_metrics; +struct glyph; + +void ft_init(void); +void ft_fini(void); +int open_font(char *fname); +void close_font(void); +int count_glyphs(void); +int glnames(struct glyph *glyph_list); +void glmetrics(struct glyph *glyph_list, void (*callback)(int progress)); +int glenc(struct glyph *glyph_list); +int fnmetrics(struct font_metrics *fm); +void glpath(int glyphno, struct glyph *glyph_list); +void kerning(struct glyph *glyph_list); + +#endif + diff --git a/src/glyph.h b/src/glyph.h new file mode 100644 index 0000000..fe91bc8 --- /dev/null +++ b/src/glyph.h @@ -0,0 +1,39 @@ +#ifndef _TTF2F_GLYPH_H_ +#define _TTF2F_GLYPH_H_ + +struct outline { + enum { TERMINATE, MOVE_TO, LINE_TO, CURVE } type; + union { + struct { int composite; } terminate; + struct { int x:12, y:12; } move_to; + struct { int x:12, y:12; } line_to; + struct { int x1:12, y1:12; + int x2:12, y2:12; + int x3:12, y3:12; } curve; + } data; + + struct outline *next; +}; + +struct composite { + short code; + short x; + short y; + struct composite *next; +}; + +struct glyph { + unsigned int code; /* glyph code */ + char *name; /* glyph name */ + int xMin:12, yMin:12; + int xMax:12, yMax:12; /* glyph control box */ + int lsb; /* left side bearing of glyph, + relative to origin */ + int ttf_pathlen; /* number of points in glyph */ + short width; /* advance width of glyph */ + struct outline *outline; /* outline of glyph */ + struct composite *composite; /* list of composite inclusions */ +}; + +#endif + diff --git a/src/glyphs.c b/src/glyphs.c new file mode 100644 index 0000000..71a8775 --- /dev/null +++ b/src/glyphs.c @@ -0,0 +1,101 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "glyphs.h" + +struct glyph_entry { + unsigned short code; + char *name; + struct glyph_entry *next; +}; + +struct glyph_entry glyphs[256]; + +void load_glyph_list(void) +{ + FILE *fp; + char line[1024]; + char *semi, *name; + struct glyph_entry *g, *cur; + + fp = fopen("<TTF2f$Dir>.Glyphs", "r"); + if (!fp) { + fprintf(stderr, "Failed opening glyphs file\n"); + exit(255); + } + + while(fgets(line, 1024, fp)) { + /* skip comments & blank lines */ + if (line[0] == 0 || line[0] == '#') + continue; + + /* strip cr from end */ + line[strlen(line) - 1] = 0; + + semi = strchr(line, ';'); + if (!semi) + continue; + *semi = 0; + name = semi+1; + semi = strchr(name, ';'); + if (semi) + *semi = 0; + + g = calloc(1, sizeof(struct glyph_entry)); + if (!g) { + fprintf(stderr, "malloc failed\n"); + exit(255); + } + + g->code = (unsigned short)strtoul(line, NULL, 16); + g->name = strdup(name); + +// fprintf(stderr, "%04.4X: %s\n", g->code, g->name); + + for (cur = &glyphs[g->code / 256]; + cur->next && cur->code < g->code; + cur = cur->next) + ; + + if (cur->code == g->code) { + free(g->name); + free(g); + continue; + } + + if (cur->next) + g->next = cur->next; + cur->next = g; + } + + fclose(fp); +} + +char *glyph_name(unsigned short code) +{ + struct glyph_entry *g; + + for (g = &glyphs[code / 256]; g; g = g->next) + if (g->code == code) + break; + + if (!g) + return NULL; + + return g->name; +} + +void destroy_glyphs(void) +{ + int i; + struct glyph_entry *a, *b; + + for (i = 0; i != 256; i++) { + for (a = (&glyphs[i])->next; a; a = b) { + b = a->next; + free(a->name); + free(a); + } + } +} diff --git a/src/glyphs.h b/src/glyphs.h new file mode 100644 index 0000000..39c3426 --- /dev/null +++ b/src/glyphs.h @@ -0,0 +1,8 @@ +#ifndef _TTF2F_GLYPHS_H_ +#define _TTF2F_GLYPHS_H_ + +void load_glyph_list(void); +char *glyph_name(unsigned short code); +void destroy_glyphs(void); + +#endif diff --git a/src/intmetrics.c b/src/intmetrics.c new file mode 100644 index 0000000..c5dbbca --- /dev/null +++ b/src/intmetrics.c @@ -0,0 +1,154 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "swis.h" + +#include "fm.h" +#include "glyph.h" +#include "intmetrics.h" +#include "utils.h" + +struct intmetrics_header { + char name[40]; + int a; + int b; + char nlo; + char version; + char flags; + char nhi; +}; + +static short mapsize; + +static char *character_map = 0; + +/* we don't use these */ +// static short *x0; +// static short *y0; +// static short *x1; +// static short *y1; + +static short *xwidthtab = 0; +// static short *ywidthtab; + +struct extra_data_offsets { + short misc; + short kern; + short res1; + short res2; +}; + +struct misc_area { + short x0; + short y0; + short x1; + short y1; + short default_x_offset; + short default_y_offset; + short italic_h_offset; + char underline_position; + char underline_thickness; + short cap_height; + short xheight; + short descender; + short ascender; + int reserved; +}; + +struct kern_pair_8 { + char left; + char right; + short x_kern; + short y_kern; + char list_end; + char area_end; +}; + +struct kern_pair_16 { + short left; + short right; + short x_kern; + short y_kern; + short list_end; + short area_end; +}; + +/** + * Write font metrics to file + * + * \param savein Location to save in + * \param name Font name + * \param glyph_list List of all glyphs in font + * \param list_size Size of glyph list + * \param metrics Global font metrics + */ +void write_intmetrics(const char *savein, const char *name, + struct glyph *glyph_list, int list_size, + struct font_metrics *metrics, + void (*callback)(int progress)) +{ + struct intmetrics_header header; + int charmap_size = 0; + unsigned int xwidthtab_size = 0; + int i; + struct glyph *g; + char out[1024]; + FILE *output; + + UNUSED(metrics); + + /* allow for chunk 0 */ + xwidthtab = calloc(33, sizeof(short)); + if (!xwidthtab) { + fprintf(stderr, "malloc failed\n"); + return; + } + xwidthtab_size = 32; + + /* create xwidthtab - char code is now the index */ + for (i = 0; i != list_size; i++) { + g = &glyph_list[i]; + + callback((i * 100) / list_size); + ttf2f_poll(1); + + xwidthtab_size++; + xwidthtab[i+32] = g->width; + xwidthtab = realloc(xwidthtab, + (xwidthtab_size+1) * sizeof(short)); + if (!xwidthtab) { + fprintf(stderr, "malloc failed\n"); + return; + } + } + + /* fill in header */ + snprintf(header.name, 40, "%s", name); + memset(header.name + (strlen(name) >= 40 ? 39 : strlen(name)), 0xD, + 40 - (strlen(name) >= 40 ? 39 : strlen(name))); + header.a = header.b = 16; + header.version = 0x2; + header.flags = 0x25; + header.nhi = xwidthtab_size / 256; + header.nlo = xwidthtab_size % 256; + + mapsize = charmap_size; + + snprintf(out, 1024, "%s.IntMetrics", savein); + output = fopen(out, "wb+"); + fwrite((void*)&header, sizeof(struct intmetrics_header), 1, output); + fputc(mapsize & 0xFF, output); + fputc((mapsize & 0xFF00) >> 8, output); + fwrite(character_map, sizeof(char), charmap_size, output); + fwrite(xwidthtab, sizeof(short), xwidthtab_size, output); + fclose(output); + + /* set type */ + _swix(OS_File, _INR(0,2), 18, out, 0xFF6); + + if (character_map) + free(character_map); + free(xwidthtab); +} + diff --git a/src/intmetrics.h b/src/intmetrics.h new file mode 100644 index 0000000..0aaf1be --- /dev/null +++ b/src/intmetrics.h @@ -0,0 +1,12 @@ +#ifndef _TTF2F_INTMETRICS_H_ +#define _TTF2F_INTMETRICS_H_ + +struct glyph; +struct font_metrics; + +void write_intmetrics(const char *savein, const char *name, + struct glyph *glyph_list, int list_size, + struct font_metrics *metrics, + void (*callback)(int progress)); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..5de9982 --- /dev/null +++ b/src/main.c @@ -0,0 +1,456 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <time.h> + +#include "swis.h" + +#include "tboxlibs/event.h" +#include "tboxlibs/gadgets.h" +#include "tboxlibs/quit.h" +#include "tboxlibs/toolbox.h" +#include "tboxlibs/wimp.h" +#include "tboxlibs/wimplib.h" + +#include "encoding.h" +#include "ft.h" +#include "fm.h" +#include "glyph.h" +#include "glyphs.h" +#include "intmetrics.h" +#include "outlines.h" +#include "utils.h" + +#define Convert_Font 0x101 + +int ttf2f_quit = 0; +MessagesFD messages_file; +ObjectId main_window; +int converting = 0; + +/* Wimp Messages we're interested in */ +static int messages [] ={ + Wimp_MDataLoad, + Wimp_MQuit, + 0}; + +/* Toolbox events we're interested in */ +static int tbcodes [] ={ + Convert_Font, + Quit_Quit, + Toolbox_Error, + 0}; + +static void ttf2f_init(int argc, char **argv); +static void ttf2f_exit(void); +static void register_toolbox_handlers(void); +static int toolbox_event_quit(int event_code, ToolboxEvent *event, + IdBlock *id_block, void *handle); +static int toolbox_event_error(int event_code, ToolboxEvent *event, + IdBlock *id_block, void *handle); +static int convert_font(int event_code, ToolboxEvent *event, + IdBlock *id_block, void *handle); +static void register_message_handlers(void); +static int wimp_message_quit(WimpMessage *message,void *handle); +static int wimp_message_dataload(WimpMessage *message,void *handle); +static void progress_bar(int value); + +int main(int argc, char **argv) +{ + ttf2f_init(argc, argv); + + while (!ttf2f_quit) + ttf2f_poll(0); + + ttf2f_exit(); + + return 0; +} + + +void ttf2f_init(int argc, char **argv) +{ + _kernel_oserror *error; + IdBlock toolbox_block; + char *stringset; + + ft_init(); + load_glyph_list(); + + error = event_initialise(&toolbox_block); + if (error) { + fprintf(stderr, "event_initialise: 0x%x: %s\n", + error->errnum, error->errmess); + exit(1); + } + + event_set_mask(Wimp_Poll_NullMask | + Wimp_Poll_PointerLeavingWindowMask | + Wimp_Poll_PointerEnteringWindowMask | + Wimp_Poll_MouseClickMask | + Wimp_Poll_KeyPressedMask | + Wimp_Poll_LoseCaretMask | + Wimp_Poll_GainCaretMask); + + register_toolbox_handlers(); + register_message_handlers(); + + error = toolbox_initialise(0, 310, messages, tbcodes, + "<TTF2F$Dir>", &messages_file, + &toolbox_block, NULL, NULL, NULL); + if (error) { + fprintf(stderr, "toolbox_initialise: 0x%x: %s\n", + error->errnum, error->errmess); + exit(1); + } + + error = toolbox_create_object(0, "main", &main_window); + if (error) { + fprintf(stderr, "toolbox_create_object: 0x%x: %s\n", + error->errnum, error->errmess); + exit(1); + } + + stringset = getenv("Font$Path"); + if (stringset) { + error = stringset_set_available(0, main_window, 7, + stringset); + if (error) { + fprintf(stderr, + "stringset_set_available: 0x%x: %s\n", + error->errnum, error->errmess); + exit(1); + } + } +} + +void ttf2f_poll(int active) +{ + _kernel_oserror *error; + int event; + unsigned int mask; + WimpPollBlock block; + + if (active || converting) { + event_set_mask(0x3972); + error = event_poll(&event, &block, 0); + } else { + event_get_mask(&mask); + event_set_mask(mask | Wimp_Poll_NullMask); + error = event_poll(&event, &block, 0); + } + if (error) + fprintf(stderr, "event_poll: 0x%x: %s\n", + error->errnum, error->errmess); +} + +void ttf2f_exit(void) +{ + _kernel_oserror *error; + + ft_fini(); + destroy_glyphs(); + + error = event_finalise(); + if (error) + fprintf(stderr, "event_finalise: 0x%x: %s\n", + error->errnum, error->errmess); +} + +/** + * Register event handlers with the toolbox + */ +void register_toolbox_handlers(void) +{ + _kernel_oserror *error; + + error = event_register_toolbox_handler(-1, Quit_Quit, + toolbox_event_quit, 0); + if (error) + fprintf(stderr, "registering Quit_Quit: 0x%x: %s\n", + error->errnum, error->errmess); + + error = event_register_toolbox_handler(-1, Toolbox_Error, + toolbox_event_error, 0); + if (error) + fprintf(stderr, "registering Quit_Quit: 0x%x: %s\n", + error->errnum, error->errmess); + + error = event_register_toolbox_handler(-1, Convert_Font, + convert_font, 0); + if (error) + fprintf(stderr, "registering Convert_Font: 0x%x: %s\n", + error->errnum, error->errmess); +} + +/** + * Handle quit events + */ +int toolbox_event_quit(int event_code, ToolboxEvent *event, + IdBlock *id_block, void *handle) +{ + ttf2f_quit = 1; + + return 1; +} + +/** + * Handle toolbox errors + */ +int toolbox_event_error(int event_code, ToolboxEvent *event, + IdBlock *id_block, void *handle) +{ + ToolboxErrorEvent *error = (ToolboxErrorEvent *)event; + + fprintf(stderr, "toolbox error: 0x%x: %s\n", + error->errnum, error->errmess); + + return 1; +} + +/** + * Register message handlers + */ +void register_message_handlers(void) +{ + _kernel_oserror *error; + + error = event_register_message_handler(Wimp_MQuit, wimp_message_quit, + 0); + if (error) + fprintf(stderr, "registering Wimp_MQuit handler: 0x%x: %s\n", + error->errnum, error->errmess); + + error = event_register_message_handler(Wimp_MDataLoad, + wimp_message_dataload, + 0); + if (error) + fprintf(stderr, + "registering Wimp_MDataLoad handler: 0x%x: %s\n", + error->errnum, error->errmess); +} + +/** + * Handle quit messages + */ +int wimp_message_quit(WimpMessage *message,void *handle) +{ + ttf2f_quit = 1; + + return 1; +} + +/** + * Handle dataload messages + */ +int wimp_message_dataload(WimpMessage *message,void *handle) +{ + _kernel_oserror *error; + WimpDataLoadMessage *dl = &message->data.data_load; + + error = displayfield_set_value(0, main_window, 0, dl->leaf_name); + if (error) { + fprintf(stderr, "displayfield_set_value: 0x%x: %s\n", + error->errnum, error->errmess); + } + + message->hdr.action_code = Wimp_MDataLoadAck; + message->hdr.your_ref = message->hdr.my_ref; + error = wimp_send_message(17, message, message->hdr.sender, 0, 0); + if (error) { + fprintf(stderr, "wimp_send_message: 0x%x: %s\n", + error->errnum, error->errmess); + } + + return 1; +} + + + + +int convert_font(int event_code, ToolboxEvent *event, + IdBlock *id_block, void *handle) +{ + _kernel_oserror *error, erblock = { 123456, "Invalid Parameters" }; + char ifilename[256], ofilename[256], save_in[1024]; + char *token; + int count = 0; + int nglyphs, i; + struct glyph *glyph_list, *g; + struct font_metrics *metrics; + + if (converting) + return 1; + + converting = 1; + + /* get input file */ + error = displayfield_get_value(0, main_window, 0, ifilename, 256, 0); + if (error) { + fprintf(stderr, "displayfield_get_value: 0x%x: %s\n", + error->errnum, error->errmess); + } + + /* read font name */ + error = writablefield_get_value(0, main_window, 3, ofilename, 256, 0); + if (error) { + fprintf(stderr, "writablefield_get_value: 0x%x: %s\n", + error->errnum, error->errmess); + } + + /* read save location */ + error = stringset_get_selected(0, main_window, 7, save_in, 1024, 0); + if (error) { + fprintf(stderr, "stringset_get_selected: 0x%x: %s\n", + error->errnum, error->errmess); + } + + /* sanity check */ + if (strcmp(save_in, "Save in") == 0 || strcmp(ofilename, "") == 0 || + strcmp(ifilename, "Filename") == 0) { + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + /* create output directories */ + token = strtok(ofilename, "."); + while (token) { + if (count) + strcat(save_in, "."); + strcat(save_in, token); + error = _swix(OS_File, _INR(0,1) | _IN(4), 8, save_in, 0); + if (error) { + fprintf(stderr, "os_file: 0x%x: %s\n", + error->errnum, error->errmess); + wimp_report_error(error, 0x5, "TTF2f"); + converting = 0; + return 1; + } + token = strtok(NULL, "."); + count++; + } + + /* re-read font name - previously corrupted by strtok */ + error = writablefield_get_value(0, main_window, 3, ofilename, 256, 0); + if (error) { + fprintf(stderr, "writablefield_get_value: 0x%x: %s\n", + error->errnum, error->errmess); + } + + if (open_font(ifilename)) { + snprintf(erblock.errmess, 252, "Unknown font format"); + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + nglyphs = count_glyphs(); + + fprintf(stderr, "%d x %d = %d\n", nglyphs, sizeof(struct glyph), nglyphs * sizeof(struct glyph)); + + glyph_list = (struct glyph *)calloc(nglyphs, sizeof(struct glyph)); + if (!glyph_list) { + fprintf(stderr, "malloc failed\n"); + snprintf(erblock.errmess, 252, "Insufficient memory"); + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + /* Initialise glyph list */ + for (i = 0; i != nglyphs; i++) { + g = &glyph_list[i]; + + g->code = -1; + } + + /* create buffer for font metrics data */ + metrics = calloc(1, sizeof(struct font_metrics)); + if (!metrics) { + free(glyph_list); + close_font(); + fprintf(stderr, "malloc failed\n"); + snprintf(erblock.errmess, 252, "Insufficient memory"); + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + /* read global font metrics */ + if (fnmetrics(metrics)) { + free(glyph_list); + free(metrics); + close_font(); + snprintf(erblock.errmess, 252, "Insufficient memory"); + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + /* map glyph ids to charcodes */ + if (glenc(glyph_list)) { + free(glyph_list); + free(metrics); + close_font(); + snprintf(erblock.errmess, 252, "Unknown encoding"); + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + /* extract glyph names */ + if (glnames(glyph_list)) { + free(glyph_list); + free(metrics); + close_font(); + snprintf(erblock.errmess, 252, "Insufficient memory"); + wimp_report_error(&erblock, 0x5, "TTF2f"); + converting = 0; + return 1; + } + + /* olive */ + slider_set_colour(0, main_window, 8, 13, 0); + + /* extract glyph metrics */ + glmetrics(glyph_list, progress_bar); + + /* red */ + slider_set_colour(0, main_window, 8, 11, 13); + + /* write intmetrics file */ + write_intmetrics(save_in, ofilename, glyph_list, nglyphs, metrics, progress_bar); + + /* blue */ + slider_set_colour(0, main_window, 8, 8, 11); + + /* write outlines file */ + write_outlines(save_in, ofilename, glyph_list, nglyphs, metrics, progress_bar); + + /* green */ + slider_set_colour(0, main_window, 8, 10, 8); + + /* write encoding file */ + write_encoding(save_in, ofilename, glyph_list, nglyphs, 0, progress_bar); + + /* reset slider */ + slider_set_colour(0, main_window, 8, 8, 0); + slider_set_value(0, main_window, 8, 0); + + free(glyph_list); + free(metrics); + + close_font(); + + converting = 0; + + return 1; +} + +void progress_bar(int value) +{ + slider_set_value(0, main_window, 8, value); +} + diff --git a/src/outlines.c b/src/outlines.c new file mode 100644 index 0000000..ffdad4f --- /dev/null +++ b/src/outlines.c @@ -0,0 +1,297 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "swis.h" + +#include "fm.h" +#include "ft.h" +#include "glyph.h" +#include "outlines.h" +#include "utils.h" + +static unsigned int write_chunk(FILE* file, int chunk_no, + struct glyph *glyph_list, int list_size); + +/** + * Write the font outlines to file + * + * \param savein Location to save in + * \param name Font name + * \param glyph_list List of all glyphs in font + * \param list_size Size of glyph list + * \param metrics Global font metrics + */ +void write_outlines(const char *savein, const char *name, + struct glyph *glyph_list, int list_size, + struct font_metrics *metrics, + void (*callback)(int progress)) +{ + struct outlines_header header; + int table_end_len, i; + unsigned int current_chunk_offset; + unsigned int chunk_table_entry; + FILE *output; + char out[1024]; + + /* length of name + \0 + "Outlines" + \0 */ + table_end_len = strlen(name) + 10; + + /* fill in file header */ + header.id = 'F' + ('O' << 8) + ('N' << 16) + ('T' << 24); + header.bpp = 0; + header.version = 8; + header.flags = 1000; /* design size of converted font */ + header.x0 = metrics->bbox[0]; + header.y0 = metrics->bbox[1]; + header.X = metrics->bbox[2] - metrics->bbox[0]; + header.Y = metrics->bbox[3] - metrics->bbox[1]; + header.chunk_data.chunk_table_offset = + sizeof(struct outlines_header) + ((table_end_len + 6) & ~3); + header.chunk_data.nchunks = (list_size / 32) + 2; + header.chunk_data.num_scaffold = 1; /* no scaffold lines */ + header.chunk_data.scaffold_flags = OUTLINES_SCAFFOLD_16BIT | + OUTLINES_SCAFFOLD_NON_ZERO_WINDING; + header.chunk_data.reserved[0] = 0; + header.chunk_data.reserved[1] = 0; + header.chunk_data.reserved[2] = 0; + header.chunk_data.reserved[3] = 0; + header.chunk_data.reserved[4] = 0; + + snprintf(out, 1024, "%s.Outlines", savein); + output = fopen(out, "wb+"); + /* write file header */ + fwrite((void*)&header, sizeof(struct outlines_header), 1, output); + /* write scaffold table */ + fputc(0x3, output); + fputc(0x0, output); + fputc(0x0, output); + /* table end */ + fprintf(output, "%s", name); + fputc(0x0, output); + fprintf(output, "Outlines"); + fputc(0x0, output); + /* word align */ + i = table_end_len + 3 + sizeof(struct outlines_header); + while (i++ < header.chunk_data.chunk_table_offset) + fputc(0x0, output); + + /* write chunk table */ + chunk_table_entry = 1; + current_chunk_offset = header.chunk_data.chunk_table_offset + + header.chunk_data.nchunks * 4 + 4; + + /* initialise chunk table */ + for (i = 0; i <= header.chunk_data.nchunks; i++) { + fwrite((void*)¤t_chunk_offset, sizeof(int), + 1, output); + } + + /* write copyright information to file */ + fputc(0x0, output); + fprintf(output, + "\n\n\n%s is %s\nConverted to RISC OS by TTF2F\n\n\n", + metrics->name_full, metrics->name_copyright); + fputc(0x0, output); + current_chunk_offset += 42 + strlen(metrics->name_full) + + strlen(metrics->name_copyright); + + while(current_chunk_offset % 4) { + fputc(0x0, output); + current_chunk_offset++; + } + + /* fill in offsets 0 and 1 */ + fseek(output, header.chunk_data.chunk_table_offset, SEEK_SET); + fwrite((void*)¤t_chunk_offset, sizeof(int), 1, output); + fwrite((void*)¤t_chunk_offset, sizeof(int), 1, output); + + for (; header.chunk_data.nchunks > 1; header.chunk_data.nchunks--) { + + callback((chunk_table_entry * 100) / ((list_size / 32) + 2)); + ttf2f_poll(1); + + /* seek to start of current chunk */ + fseek(output, current_chunk_offset, SEEK_SET); + + /* write chunk */ + current_chunk_offset += write_chunk(output, + chunk_table_entry - 1, glyph_list, + list_size); + + /* align to word boundary */ + while (current_chunk_offset % 4) { + fputc(0x0, output); + current_chunk_offset++; + } + + /* fill in next chunk table entry */ + fseek(output, header.chunk_data.chunk_table_offset + + (chunk_table_entry+1) * 4, SEEK_SET); + fwrite((void*)¤t_chunk_offset, sizeof(int), 1, + output); + + chunk_table_entry++; + } + + fclose(output); + + /* set type */ + _swix(OS_File, _INR(0,2), 18, out, 0xFF6); +} + +/** + * Write chunk to outlines file + * + * \param file Stream handle + * \param chunk_no The current chunk number (0..nchunks-1) + * \param glyph_list List of all glyphs in font + * \param list_size Size of glyph list + * \return Size of this chunk, or 0 on failure + */ +unsigned int write_chunk(FILE* file, int chunk_no, struct glyph *glyph_list, + int list_size) +{ + struct glyph *g; + struct chunk *chunk; + unsigned int chunk_size; + struct outline *o, *next; + struct char_data *character; + int i; + + /* create chunk */ + chunk = calloc(1, sizeof(struct chunk)); + if (!chunk) + return 0; + + chunk->flags = 0x80000000; + + chunk_size = sizeof(struct chunk); + + /* 32 chars in each chunk */ + for (i = 0; i != 32; i++) { + + ttf2f_poll(1); + + if ((chunk_no * 32) + i >= list_size) + /* exit if we've reached the end of the input */ + break; + + /* get glyph */ + g = &glyph_list[(chunk_no * 32) + i]; + + /* no path => skip character */ + if (g->ttf_pathlen == 0) { + chunk->offset[i] = 0; + continue; + } + + /* offset from index start */ + chunk->offset[i] = chunk_size - 4; + + chunk = realloc((char*)chunk, + chunk_size+sizeof(struct char_data)); + if (!chunk) + return 0; + character = (struct char_data*)(void*)((char*)chunk + chunk_size); + + chunk_size += sizeof(struct char_data); + + character->flags = CHAR_12BIT_COORDS | CHAR_OUTLINE; + /* character x0, y0 */ + character->x0y0[0] = g->xMin & 0xFF; + character->x0y0[1] = ((g->yMin << 4) & 0xF0) | + ((g->xMin >> 8) & 0xF); + character->x0y0[2] = (g->yMin >> 4) & 0xFF; + /* character width, height */ + character->xsys[0] = (g->xMax - g->xMin) & 0xFF; + character->xsys[1] = (((g->yMax - g->yMin) << 4) & 0xF) | + (((g->xMax - g->xMin) >> 8) & 0xF); + character->xsys[2] = ((g->yMax - g->yMin) >> 4) & 0xFF; + + /* decompose glyph path */ + glpath((chunk_no * 32) + i, glyph_list); + + for (o = g->outline; o; o = next) { + if (!o) + break; + + /* movement type */ + switch (o->type) { + case TERMINATE: + /* end of outline */ + chunk = realloc((char*)chunk, + chunk_size+1); + if (!chunk) + return 0; + *((char*)chunk+chunk_size-1) = 0; + chunk_size += 1; + break; + case MOVE_TO: + /* move to point */ + chunk = realloc((char*)chunk, + chunk_size+4); + if (!chunk) + return 0; + /* id, no scaffold */ + *((char*)chunk+chunk_size-1) = 1; + /* x, y */ + *((char*)chunk+chunk_size) = o->data.move_to.x & 0xFF; + *((char*)chunk+chunk_size+1) = (((o->data.move_to.y << 4) & 0xF0) | ((o->data.move_to.x >> 8) & 0xF)); + *((char*)chunk+chunk_size+2) = (o->data.move_to.y >> 4) & 0xFF; + chunk_size += 4; + break; + case LINE_TO: + /* draw line to point */ + chunk = realloc((char*)chunk, + chunk_size+4); + if (!chunk) + return 0; + /* id, no scaffold */ + *((char*)chunk+chunk_size-1) = 2; + /* x, y */ + *((char*)chunk+chunk_size) = o->data.line_to.x & 0xFF; + *((char*)chunk+chunk_size+1) = (((o->data.line_to.y << 4) & 0xF0) | ((o->data.line_to.x >> 8) & 0xF)); + *((char*)chunk+chunk_size+2) = (o->data.line_to.y >> 4) & 0xFF; + chunk_size += 4; + break; + case CURVE: + /* draw bezier curve to point */ + chunk = realloc((char*)chunk, + chunk_size+10); + if (!chunk) + return 0; + /* id, no scaffold */ + *((char*)chunk+chunk_size-1) = 3; + /* x1, y1 */ + *((char*)chunk+chunk_size) = o->data.curve.x1 & 0xFF; + *((char*)chunk+chunk_size+1) = (((o->data.curve.y1 << 4) & 0xF0) | ((o->data.curve.x1 >> 8) & 0xF)); + *((char*)chunk+chunk_size+2) = (o->data.curve.y1 >> 4) & 0xFF; + /* x2, y2 */ + *((char*)chunk+chunk_size+3) = o->data.curve.x2 & 0xFF; + *((char*)chunk+chunk_size+4) = (((o->data.curve.y2 << 4) & 0xF0) | ((o->data.curve.x2 >> 8) & 0xF)); + *((char*)chunk+chunk_size+5) = (o->data.curve.y2 >> 4) & 0xFF; + /* x3, y3 */ + *((char*)chunk+chunk_size+6) = o->data.curve.x3 & 0xFF; + *((char*)chunk+chunk_size+7) = (((o->data.curve.y3 << 4) & 0xF0) | ((o->data.curve.x3 >> 8) & 0xF)); + *((char*)chunk+chunk_size+8) = (o->data.curve.y3 >> 4) & 0xFF; + chunk_size += 10; + break; + } + + next = o->next; + free(o); + } + + /* shift chunk end pointer to end of character */ + chunk_size -= 1; + } + + /* write chunk to file */ + fwrite((void*)chunk, chunk_size, 1, file); + + free(chunk); + + return chunk_size; +} + diff --git a/src/outlines.h b/src/outlines.h new file mode 100644 index 0000000..99a916b --- /dev/null +++ b/src/outlines.h @@ -0,0 +1,58 @@ +#ifndef _TTF2F_OUTLINES_H_ +#define _TTF2F_OUTLINES_H_ + +struct chunk_data { + int chunk_table_offset; + int nchunks; + int num_scaffold; + int scaffold_flags; + int reserved[5]; +}; + +struct outlines_header { + int id; + char bpp; + char version; + short flags; + short x0; + short y0; + short X; + short Y; + struct chunk_data chunk_data; +}; + +#define OUTLINES_SCAFFOLD_16BIT 0x1 +#define OUTLINES_SCAFFOLD_NO_AA 0x2 +#define OUTLINES_SCAFFOLD_NON_ZERO_WINDING 0x4 +#define OUTLINES_SCAFFOLD_BIG_TABLE 0x8 + +struct chunk { + unsigned int flags; + unsigned int offset[32]; + unsigned char depend[4]; +}; + +struct char_data { + char flags; + char x0y0[3]; + char xsys[3]; +}; + +#define CHAR_12BIT_COORDS 0x01 +#define CHAR_1BPP 0x02 +#define CHAR_BLACK 0x04 +#define CHAR_OUTLINE 0x08 +#define CHAR_COMPOSITE 0x10 +#define CHAR_HAS_ACCENT 0x20 +#define CHAR_16BIT_ASCII 0x40 +#define CHAR_RESERVED 0x80 + +struct glyph; +struct font_metrics; + +void write_outlines(const char *savein, const char *name, + struct glyph *glyph_list, int list_size, + struct font_metrics *metrics, + void (*callback)(int progress)); + +#endif diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..1aea66f --- /dev/null +++ b/src/utils.c @@ -0,0 +1,39 @@ +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" + +char *strndup(const char *s, size_t n) +{ + /* this assumes s is NUL terminated - if not, + * some silly value will be returned */ + size_t len = strlen(s); + char *res; + + /* limit to n */ + if (len > n || n == 0) + len = n; + + res = (char *) malloc(len + 1); + if (res == NULL) + return NULL; + + res[len] = '\0'; + return (char *) memcpy(res, s, len); +} + +/** + * Convert raw font units to units normalised with a design size of 1000 + * + * \param raw Raw value from file + * \param ppem Design size of font + * \return Converted value + */ +long convert_units(long raw, long ppem) +{ + if (ppem == 1000) + return raw; + + return (raw * 1000) / ppem; +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 0000000..8837255 --- /dev/null +++ b/src/utils.h @@ -0,0 +1,12 @@ +#ifndef _TTF2F_UTILS_H_ +#define _TTF2F_UTILS_H_ + +#ifndef UNUSED +#define UNUSED(x) ((x)=(x)) +#endif + +void ttf2f_poll(int active); +char *strndup(const char *s, size_t n); +long convert_units(long raw, long ppem); + +#endif |