#include <time.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#ifndef __UNIXOS2__
# include <math.h>
#else
# include <float.h>
#endif
#include <stdarg.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_BDF_H
#include "X11/Xos.h"
#include "fonttosfnt.h"
#ifdef NEED_SNPRINTF
#undef SCOPE
#define SCOPE static
#include "snprintf.c"
#endif
#ifdef __GLIBC__
#define HAVE_TIMEGM
#define HAVE_TM_GMTOFF
#endif
#ifdef BSD
#define HAVE_TM_GMTOFF
#define GMTOFFMEMBER tm_gmtoff
#endif
#ifdef __SCO__
#define HAVE_TM_GMTOFF
#define GMTOFFMEMBER tm_tzadj
#endif
#define HAVE_TZSET
#ifdef NEED_SETENV
extern int setenv(const char *name, const char *value, int overwrite);
extern void unsetenv(const char *name);
#endif
char*
sprintf_alloc(char *f, ...)
{
char *s;
va_list args;
va_start(args, f);
s = vsprintf_alloc(f, args);
va_end(args);
return s;
}
#if HAVE_VASPRINTF
char*
vsprintf_alloc(char *f, va_list args)
{
char *r;
int rc;
rc = vasprintf(&r, f, args);
if(rc < 0)
return NULL;
return r;
}
#else
char*
vsprintf_alloc(char *f, va_list args)
{
int n, size = 12;
char *string;
va_list args_copy;
while(1) {
if(size > 4096)
return NULL;
string = malloc(size);
if(!string)
return NULL;
#if HAVE_DECL_VA_COPY
va_copy(args_copy, args);
n = vsnprintf(string, size, f, args_copy);
#else
n = vsnprintf(string, size, f, args);
#endif
if(n >= 0 && n < size)
return string;
else if(n >= size)
size = n + 1;
else
size = size * 3 / 2 + 1;
free(string);
}
}
#endif
char *
makeUTF16(char *string)
{
int i;
int n = strlen(string);
char *value = malloc(2 * n);
if(!value)
return NULL;
for(i = 0; i < n; i++) {
value[2 * i] = '\0';
value[2 * i + 1] = string[i];
}
return value;
}
unsigned
makeName(char *s)
{
return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
}
#if defined(HAVE_TIMEGM)
static time_t
mktime_gmt(struct tm *tm)
{
return timegm(tm);
}
#elif defined(HAVE_TM_GMTOFF)
static time_t
mktime_gmt(struct tm *tm)
{
time_t t;
struct tm *ltm;
t = mktime(tm);
if(t < 0)
return -1;
ltm = localtime(&t);
if(ltm == NULL)
return -1;
return t + ltm->GMTOFFMEMBER;
}
#elif defined(HAVE_TZSET)
static time_t
mktime_gmt(struct tm *tm)
{
time_t t;
char *tz;
tz = getenv("TZ");
setenv("TZ", "", 1);
tzset();
t = mktime(tm);
if(tz)
setenv("TZ", tz, 1);
else
unsetenv("TZ");
tzset();
return t;
}
#else
#error no mktime_gmt implementation on this platform
#endif
int
macTime(int *hi, unsigned *lo)
{
unsigned long diff;
time_t macEpoch, current;
struct tm tm;
tm.tm_sec = 0;
tm.tm_min = 0;
tm.tm_hour = 0;
tm.tm_mday = 1;
tm.tm_mon = 1;
tm.tm_year = 4;
tm.tm_isdst = -1;
macEpoch = mktime_gmt(&tm);
if(macEpoch < 0) return -1;
current = time(NULL);
if(current < 0)
return -1;
if(current < macEpoch) {
errno = EINVAL;
return -1;
}
diff = current - macEpoch;
#if INT_MAX == LONG_MAX
*hi = 0;
#else
*hi = diff >> 32;
#endif
*lo = diff & 0xFFFFFFFF;
return 0;
}
unsigned
faceFoundry(FT_Face face)
{
int rc;
BDF_PropertyRec prop;
rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
if(strcasecmp(prop.u.atom, "adobe") == 0)
return makeName("ADBE");
else if(strcasecmp(prop.u.atom, "agfa") == 0)
return makeName("AGFA");
else if(strcasecmp(prop.u.atom, "altsys") == 0)
return makeName("ALTS");
else if(strcasecmp(prop.u.atom, "apple") == 0)
return makeName("APPL");
else if(strcasecmp(prop.u.atom, "arphic") == 0)
return makeName("ARPH");
else if(strcasecmp(prop.u.atom, "alltype") == 0)
return makeName("ATEC");
else if(strcasecmp(prop.u.atom, "b&h") == 0)
return makeName("B&H ");
else if(strcasecmp(prop.u.atom, "bitstream") == 0)
return makeName("BITS");
else if(strcasecmp(prop.u.atom, "dynalab") == 0)
return makeName("DYNA");
else if(strcasecmp(prop.u.atom, "ibm") == 0)
return makeName("IBM ");
else if(strcasecmp(prop.u.atom, "itc") == 0)
return makeName("ITC ");
else if(strcasecmp(prop.u.atom, "interleaf") == 0)
return makeName("LEAF");
else if(strcasecmp(prop.u.atom, "impress") == 0)
return makeName("IMPR");
else if(strcasecmp(prop.u.atom, "larabiefonts") == 0)
return makeName("LARA");
else if(strcasecmp(prop.u.atom, "linotype") == 0)
return makeName("LINO");
else if(strcasecmp(prop.u.atom, "monotype") == 0)
return makeName("MT ");
else if(strcasecmp(prop.u.atom, "microsoft") == 0)
return makeName("MS ");
else if(strcasecmp(prop.u.atom, "urw") == 0)
return makeName("URW ");
else if(strcasecmp(prop.u.atom, "y&y") == 0)
return makeName("Y&Y ");
else
return makeName("UNKN");
}
return makeName("UNKN");
}
int
faceWeight(FT_Face face)
{
int rc;
BDF_PropertyRec prop;
rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
if(strcasecmp(prop.u.atom, "thin") == 0)
return 100;
else if(strcasecmp(prop.u.atom, "extralight") == 0)
return 200;
else if(strcasecmp(prop.u.atom, "light") == 0)
return 300;
else if(strcasecmp(prop.u.atom, "medium") == 0)
return 500;
else if(strcasecmp(prop.u.atom, "semibold") == 0)
return 600;
else if(strcasecmp(prop.u.atom, "bold") == 0)
return 700;
else if(strcasecmp(prop.u.atom, "extrabold") == 0)
return 800;
else if(strcasecmp(prop.u.atom, "black") == 0)
return 900;
else
return 500;
} else
return 500;
}
int
faceWidth(FT_Face face)
{
int rc;
BDF_PropertyRec prop;
rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
if(strcasecmp(prop.u.atom, "ultracondensed") == 0)
return 1;
else if(strcasecmp(prop.u.atom, "extracondensed") == 0)
return 2;
else if(strcasecmp(prop.u.atom, "condensed") == 0)
return 3;
else if(strcasecmp(prop.u.atom, "semicondensed") == 0)
return 4;
else if(strcasecmp(prop.u.atom, "normal") == 0)
return 5;
else if(strcasecmp(prop.u.atom, "semiexpanded") == 0)
return 6;
else if(strcasecmp(prop.u.atom, "expanded") == 0)
return 7;
else if(strcasecmp(prop.u.atom, "extraexpanded") == 0)
return 8;
else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0)
return 9;
else
return 5;
} else
return 5;
}
int
faceItalicAngle(FT_Face face)
{
int rc;
BDF_PropertyRec prop;
rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) {
return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64);
}
rc = FT_Get_BDF_Property(face, "SLANT", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
if(strcasecmp(prop.u.atom, "i") == 0 ||
strcasecmp(prop.u.atom, "s") == 0)
return -30 * TWO_SIXTEENTH;
else
return 0;
} else
return 0;
}
int
faceFlags(FT_Face face)
{
int flags = 0;
BDF_PropertyRec prop;
int rc;
if(faceWeight(face) >= 650)
flags |= FACE_BOLD;
rc = FT_Get_BDF_Property(face, "SLANT", &prop);
if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
if(strcasecmp(prop.u.atom, "i") == 0 ||
strcasecmp(prop.u.atom, "s") == 0)
flags |= FACE_ITALIC;
}
return flags;
}
char *
faceEncoding(FT_Face face)
{
BDF_PropertyRec p1, p2;
int rc;
rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1);
if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM)
return NULL;
rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2);
if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM)
return NULL;
return sprintf_alloc("%s-%s", p1.u.atom, p2.u.atom);
}
int
degreesToFraction(int deg, int *num, int *den)
{
double n, d;
double rad, val;
int i;
if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH))
goto fail;
rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI;
n = sin(-rad);
d = cos(rad);
if(d < 0.001)
goto fail;
val = atan2(n, d);
for(i = 1; i < 10000; i++) {
if((int)(d * i) != 0.0 &&
fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) {
*num = (int)ROUND(n * i);
*den = (int)ROUND(d * i);
return 0;
}
}
fail:
*den = 1;
*num = 0;
return -1;
}