blob: d98c47c9e8ec68f1641c02c29f2b2f17c858e40d [file] [log] [blame]
/*
* $Id$
*
* Copyright © 2004 Keith Packard
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of Keith Packard not be used in
* advertising or publicity pertaining to distribution of the software without
* specific, written prior permission. Keith Packard makes no
* representations about the suitability of this software for any purpose. It
* is provided "as is" without express or implied warranty.
*
* KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
* EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
* DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
#include "twin_ttf.h"
static double pos (FT_Pos x, outline_closure_t *c)
{
FT_Face face = c->face;
return (double) x / (double) face->units_per_EM;
}
static void command (char cmd, outline_closure_t *c)
{
printf ("\t'%c', ", cmd);
c->offset++;
}
static int conv (FT_Pos x, outline_closure_t *c)
{
return floor(64.0 * pos (x, c) + 0.5);
}
static void cpos (FT_Pos x, outline_closure_t *c)
{
printf ("%d, ", conv(x, c));
c->offset++;
}
static unsigned char * ucs4_to_utf8 (FT_ULong ucs4,
unsigned char dest[8])
{
int bits;
unsigned char *d = dest;
if (ucs4 < 0x80) { *d++= ucs4; bits= -6; }
else if (ucs4 < 0x800) { *d++= ((ucs4 >> 6) & 0x1F) | 0xC0; bits= 0; }
else if (ucs4 < 0x10000) { *d++= ((ucs4 >> 12) & 0x0F) | 0xE0; bits= 6; }
else if (ucs4 < 0x200000) { *d++= ((ucs4 >> 18) & 0x07) | 0xF0; bits= 12; }
else if (ucs4 < 0x4000000) { *d++= ((ucs4 >> 24) & 0x03) | 0xF8; bits= 18; }
else if (ucs4 < 0x80000000) { *d++= ((ucs4 >> 30) & 0x01) | 0xFC; bits= 24; }
else return 0;
for ( ; bits >= 0; bits-= 6) {
*d++= ((ucs4 >> bits) & 0x3F) | 0x80;
}
*d++ = '\0';
return dest;
}
static void glyph (FT_GlyphSlot glyph, FT_ULong ucs4, outline_closure_t *c)
{
FT_Pos advance = glyph->linearHoriAdvance;
unsigned char utf8[8];
printf (" /* 0x%lx (%s) */ \n", ucs4, ucs4_to_utf8 (ucs4, utf8));
/* I'm very unusre about the metrics here, mostly because I'm not 100%
* confident what twin expects in some of those fields
*
* twin wants: left, right, ascent, descent.
*
* For now, I'm setting "left" to horiBearingX though I'm not quite sure
* what this is used for, "right" to the full horizontal advance of
* the glyph as that's what twin uses as an advance between characters,
* "ascent" I set to horiBearingY (unsure there too though) and for the
* last, descent, I suppose I should use the total height minus the ascent
* though I'm not sure how to retreive the former (bbox ?).
*
* Note that currently, we only support horizontal text.
*/
cpos (glyph->metrics.horiBearingX, c); /* left, not sure about that */
cpos (advance, c); /* right */
cpos (glyph->metrics.horiBearingY, c); /* ascent, not sure either */
cpos (0 /* XXX */, c); /* descent, not handled now */
printf ("\n");
}
static int outline_moveto (const FT_Vector *to, void *user)
{
outline_closure_t *c = user;
command ('m', c); cpos (to->x, c); cpos (-to->y, c);
printf ("\n");
return 0;
}
static int outline_lineto (const FT_Vector *to, void *user)
{
outline_closure_t *c = user;
command ('l', c); cpos (to->x, c); cpos (-to->y, c);
printf ("\n");
return 0;
}
static int outline_conicto (const FT_Vector *control, const FT_Vector *to,
void *user)
{
outline_closure_t *c = user;
command ('2', c);
cpos (control->x, c); cpos (0-control->y, c);
cpos (to->x, c); cpos (0-to->y, c);
printf ("\n");
return 0;
}
static int outline_cubicto (const FT_Vector *control1,
const FT_Vector *control2,
const FT_Vector *to,
void *user)
{
outline_closure_t *c = user;
command ('2', c);
cpos (control1->x, c); cpos (0-control1->y, c);
cpos (control2->x, c); cpos (0-control2->y, c);
cpos (to->x, c); cpos (0-to->y, c);
printf ("\n");
return 0;
}
static const FT_Outline_Funcs outline_funcs = {
.move_to = outline_moveto,
.line_to = outline_lineto,
.conic_to = outline_conicto,
.cubic_to = outline_cubicto,
.shift = 0,
.delta = 0
};
#define UCS_PAGE_SHIFT 7
#define UCS_PER_PAGE (1 << UCS_PAGE_SHIFT)
static int ucs_page (FT_ULong ucs4)
{
return ucs4 >> UCS_PAGE_SHIFT;
}
static FT_ULong ucs_first_in_page (FT_ULong ucs4)
{
return ucs4 & ~(UCS_PER_PAGE - 1);
}
static void sanitize (char *in, char *out, int first)
{
char c;
while ((c = *in++))
{
if (('a' <= c && c <= 'z') ||
('A' <= c && c <= 'Z') ||
('c' == '_'))
;
else if ('0' <= c && c <= '9')
{
if (first)
*out++ = '_';
}
else
c = '_';
*out++ = c;
first = 0;
}
*out++ = '\0';
}
static char * facename (FT_Face face)
{
char *family = face->family_name;
char *style = face->style_name;
char *name = malloc (1 + strlen (family) + 1 + strlen (style) + 1);
sanitize (family, name, 1);
strcat (name, "_");
sanitize (style, name + strlen (name), 0);
return name;
}
#define MAX_UCS4 0x1000000
static int convert_font (char *in_name, int id)
{
FT_Library ftLibrary;
FT_Face face;
FT_UInt gindex;
FT_ULong ucs4;
FT_Int32 load_flags;
outline_closure_t closure;
FT_ULong min_ucs4, max_ucs4;
int *offsets;
int ncharmap;
if (FT_Init_FreeType (&ftLibrary))
return 0;
if (FT_New_Face (ftLibrary, in_name, id, &face))
return 0;
if (FT_Select_Charmap (face, ft_encoding_unicode))
return 0;
load_flags = FT_LOAD_NO_SCALE|FT_LOAD_LINEAR_DESIGN;
closure.face = face;
closure.offset = 0;
offsets = calloc (face->num_glyphs + 1, sizeof (int));
min_ucs4 = 0xffffff;
max_ucs4 = 0;
printf ("/* Derived from %s */\n\n", in_name);
printf ("#include <libtwin/twin.h>\n\n");
printf ("static const signed char outlines[] = {\n");
for (ucs4 = FT_Get_First_Char (face, &gindex);
gindex != 0 && ucs4 < MAX_UCS4;
ucs4 = FT_Get_Next_Char (face, ucs4, &gindex))
{
if (FT_Load_Glyph (face, gindex, load_flags) != 0)
continue;
if (ucs4 < min_ucs4)
min_ucs4 = ucs4;
if (ucs4 > max_ucs4)
max_ucs4 = ucs4;
//offsets[gindex] = closure.offset + 1;
offsets[gindex] = closure.offset;
glyph (face->glyph, ucs4, &closure);
FT_Outline_Decompose (&face->glyph->outline, &outline_funcs, &closure);
command ('e', &closure); printf ("\n");
}
printf ("};\n\n");
printf ("static const twin_charmap_t charmap[] = {\n");
ncharmap = 0;
for (ucs4 = FT_Get_First_Char (face, &gindex);
gindex != 0 && ucs4 < MAX_UCS4;
ucs4 = FT_Get_Next_Char (face, ucs4, &gindex))
{
FT_ULong page = ucs_first_in_page (ucs4);
FT_ULong off;
printf (" { 0x%04x, {\n", ucs_page (page));
for (off = 0; off < UCS_PER_PAGE; off++)
{
FT_UInt g = FT_Get_Char_Index (face, page + off);
if ((off & 7) == 0)
printf ("\t");
printf ("0x%04x, ", offsets[g]);
if ((off & 7) == 7)
printf ("\n");
}
printf (" }},\n");
ucs4 = page + UCS_PER_PAGE - 1;
ncharmap++;
}
printf ("};\n\n");
printf ("twin_font_t twin_%s = {\n", facename (face));
printf ("\t.type\t\t= TWIN_FONT_TYPE_TTF,\n");
printf ("\t.name\t\t= \"%s\",\n", face->family_name);
printf ("\t.style\t\t= \"%s\",\n", face->style_name);
printf ("\t.n_charmap\t= %d,\n", ncharmap);
printf ("\t.charmap\t= charmap,\n");
printf ("\t.outlines\t= outlines,\n");
printf ("\t.ascender\t= %d,\n", conv (face->ascender, &closure));
printf ("\t.descender\t= %d,\n", conv (face->descender, &closure));
printf ("\t.height\t\t= %d,\n", conv (face->height, &closure));
printf ("};\n");
return 1;
}
int main (int argc, char **argv)
{
convert_font (argv[1], 0);
return 0;
}