summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Mark Bell <jmb@netsurf-browser.org>2009-05-07 15:22:02 +0000
committerJohn Mark Bell <jmb@netsurf-browser.org>2009-05-07 15:22:02 +0000
commita98d8fb5e49436c6fedea37797225293284b9894 (patch)
treef140662044f20668b937c9f3b451c56345678108 /src
downloadttf2f-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/Makefile4
-rw-r--r--src/encoding.c71
-rw-r--r--src/encoding.h11
-rw-r--r--src/fm.h31
-rw-r--r--src/ft.c569
-rw-r--r--src/ft.h20
-rw-r--r--src/glyph.h39
-rw-r--r--src/glyphs.c101
-rw-r--r--src/glyphs.h8
-rw-r--r--src/intmetrics.c154
-rw-r--r--src/intmetrics.h12
-rw-r--r--src/main.c456
-rw-r--r--src/outlines.c297
-rw-r--r--src/outlines.h58
-rw-r--r--src/utils.c39
-rw-r--r--src/utils.h12
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*)&current_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*)&current_chunk_offset, sizeof(int), 1, output);
+ fwrite((void*)&current_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*)&current_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