util.c revision d2f28e1b
1/*
2Copyright (c) 2002-2003 by Juliusz Chroboczek
3
4Permission is hereby granted, free of charge, to any person obtaining a copy
5of this software and associated documentation files (the "Software"), to deal
6in the Software without restriction, including without limitation the rights
7to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8copies of the Software, and to permit persons to whom the Software is
9furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20THE SOFTWARE.
21*/
22/* $XdotOrg: xc/programs/fonttosfnt/util.c,v 1.11 2003/12/19 02:16:36 dawes Exp $ */
23/* $XFree86: xc/programs/fonttosfnt/util.c,v 1.10 2003/12/19 02:05:39 dawes Exp $ */
24
25#include <time.h>
26#include <string.h>
27#include <errno.h>
28#include <stdlib.h>
29#ifndef __UNIXOS2__
30# include <math.h>
31#else
32# include <float.h>
33#endif
34#include <stdarg.h>
35
36#include <ft2build.h>
37#include FT_FREETYPE_H
38#include FT_BDF_H
39#include "X11/Xos.h"
40#include "X11/Xfuncproto.h" /* for _X_ATTRIBUTE_PRINTF */
41#include "fonttosfnt.h"
42
43#ifdef NEED_SNPRINTF
44#undef SCOPE
45#define SCOPE static
46#include "snprintf.c"
47#endif
48
49#ifdef __GLIBC__
50#define HAVE_TIMEGM
51#define HAVE_TM_GMTOFF
52#endif
53
54#ifdef BSD
55#define HAVE_TM_GMTOFF
56#define GMTOFFMEMBER tm_gmtoff
57#endif
58
59#ifdef __SCO__
60#define HAVE_TM_GMTOFF
61#define GMTOFFMEMBER tm_tzadj
62#endif
63
64/* That's in POSIX */
65#define HAVE_TZSET
66
67#ifdef NEED_SETENV
68extern int setenv(const char *name, const char *value, int overwrite);
69extern void unsetenv(const char *name);
70#endif
71
72char*
73sprintf_alloc(const char *f, ...)
74{
75    char *s;
76    va_list args;
77    va_start(args, f);
78    s = vsprintf_alloc(f, args);
79    va_end(args);
80    return s;
81}
82
83#if HAVE_VASPRINTF
84_X_ATTRIBUTE_PRINTF(1, 0)
85char*
86vsprintf_alloc(const char *f, va_list args)
87{
88    char *r;
89    int rc;
90
91    rc = vasprintf(&r, f, args);
92    if(rc < 0)
93        return NULL;
94    return r;
95}
96#else
97_X_ATTRIBUTE_PRINTF(1, 0)
98char*
99vsprintf_alloc(const char *f, va_list args)
100{
101    int n, size = 12;
102    char *string;
103    va_list args_copy;
104
105    while(1) {
106        if(size > 4096)
107            return NULL;
108        string = malloc(size);
109        if(!string)
110            return NULL;
111
112#if HAVE_DECL_VA_COPY
113        va_copy(args_copy, args);
114        n = vsnprintf(string, size, f, args_copy);
115#else
116        n = vsnprintf(string, size, f, args);
117#endif
118        if(n >= 0 && n < size)
119            return string;
120        else if(n >= size)
121            size = n + 1;
122        else
123            size = size * 3 / 2 + 1;
124        free(string);
125    }
126    /* NOTREACHED */
127}
128#endif
129
130/* Build a UTF-16 string from a Latin-1 string.
131   Result is not NUL-terminated. */
132char *
133makeUTF16(const char *string)
134{
135    int i;
136    int n = strlen(string);
137    char *value = malloc(2 * n);
138    if(!value)
139        return NULL;
140    for(i = 0; i < n; i++) {
141        value[2 * i] = '\0';
142        value[2 * i + 1] = string[i];
143    }
144    return value;
145}
146
147unsigned
148makeName(const char *s)
149{
150    return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
151}
152
153/* Like mktime(3), but UTC rather than local time */
154#if defined(HAVE_TIMEGM)
155static time_t
156mktime_gmt(struct tm *tm)
157{
158    return timegm(tm);
159}
160#elif defined(HAVE_TM_GMTOFF)
161static time_t
162mktime_gmt(struct tm *tm)
163{
164    time_t t;
165    struct tm *ltm;
166
167    t = mktime(tm);
168    if(t < 0)
169        return -1;
170    ltm = localtime(&t);
171    if(ltm == NULL)
172        return -1;
173    return t + ltm->GMTOFFMEMBER;
174}
175#elif defined(HAVE_TZSET)
176/* Taken from the Linux timegm(3) man page */
177static time_t
178mktime_gmt(struct tm *tm)
179{
180    time_t t;
181    char *tz;
182
183    tz = getenv("TZ");
184    setenv("TZ", "", 1);
185    tzset();
186    t = mktime(tm);
187    if(tz)
188        setenv("TZ", tz, 1);
189    else
190        unsetenv("TZ");
191    tzset();
192    return t;
193}
194#else
195#error no mktime_gmt implementation on this platform
196#endif
197
198/* Return the current time as a signed 64-bit number of seconds since
199   midnight, 1 January 1904.  This is apparently when the Macintosh
200   was designed. */
201int
202macTime(int *hi, unsigned *lo)
203{
204    unsigned long diff;		/* Not time_t */
205    time_t macEpoch, current;
206    struct tm tm;
207    tm.tm_sec = 0;
208    tm.tm_min = 0;
209    tm.tm_hour = 0;
210    tm.tm_mday = 1;
211    tm.tm_mon = 1;
212    tm.tm_year = 4;
213    tm.tm_isdst = -1;
214
215    macEpoch = mktime_gmt(&tm);
216    if(macEpoch == -1) return -1;
217
218    current = time(NULL);
219    if(current == -1)
220        return -1;
221
222    if(current < macEpoch) {
223        errno = EINVAL;
224        return -1;
225    }
226
227    diff = current - macEpoch;
228#if INT_MAX == LONG_MAX
229    *hi = 0;
230#else
231    *hi = diff >> 32;
232#endif
233    *lo = diff & 0xFFFFFFFF;
234    return 0;
235}
236
237unsigned
238faceFoundry(FT_Face face)
239{
240    int rc;
241    BDF_PropertyRec prop;
242
243    rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
244    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
245        if(strcasecmp(prop.u.atom, "adobe") == 0)
246            return makeName("ADBE");
247        else if(strcasecmp(prop.u.atom, "agfa") == 0)
248            return makeName("AGFA");
249        else if(strcasecmp(prop.u.atom, "altsys") == 0)
250            return makeName("ALTS");
251        else if(strcasecmp(prop.u.atom, "apple") == 0)
252            return makeName("APPL");
253        else if(strcasecmp(prop.u.atom, "arphic") == 0)
254            return makeName("ARPH");
255        else if(strcasecmp(prop.u.atom, "alltype") == 0)
256            return makeName("ATEC");
257        else if(strcasecmp(prop.u.atom, "b&h") == 0)
258            return makeName("B&H ");
259        else if(strcasecmp(prop.u.atom, "bitstream") == 0)
260            return makeName("BITS");
261        else if(strcasecmp(prop.u.atom, "dynalab") == 0)
262            return makeName("DYNA");
263        else if(strcasecmp(prop.u.atom, "ibm") == 0)
264            return makeName("IBM ");
265        else if(strcasecmp(prop.u.atom, "itc") == 0)
266            return makeName("ITC ");
267        else if(strcasecmp(prop.u.atom, "interleaf") == 0)
268            return makeName("LEAF");
269        else if(strcasecmp(prop.u.atom, "impress") == 0)
270            return makeName("IMPR");
271        else if(strcasecmp(prop.u.atom, "larabiefonts") == 0)
272            return makeName("LARA");
273        else if(strcasecmp(prop.u.atom, "linotype") == 0)
274            return makeName("LINO");
275        else if(strcasecmp(prop.u.atom, "monotype") == 0)
276            return makeName("MT  ");
277        else if(strcasecmp(prop.u.atom, "microsoft") == 0)
278            return makeName("MS  ");
279        else if(strcasecmp(prop.u.atom, "urw") == 0)
280            return makeName("URW ");
281        else if(strcasecmp(prop.u.atom, "y&y") == 0)
282            return makeName("Y&Y ");
283        else {
284	    char buf[5];
285	    snprintf(buf, sizeof(buf), "%-4s", prop.u.atom);
286            return makeName(buf);
287	}
288    }
289    /* For now */
290    return makeName("UNKN");
291}
292
293
294int
295faceWeight(FT_Face face)
296{
297    int rc;
298    BDF_PropertyRec prop;
299    rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop);
300    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
301        if(strcasecmp(prop.u.atom, "thin") == 0)
302            return 100;
303        else if(strcasecmp(prop.u.atom, "extralight") == 0)
304            return 200;
305        else if(strcasecmp(prop.u.atom, "light") == 0)
306            return 300;
307        else if(strcasecmp(prop.u.atom, "medium") == 0)
308            return 400;
309        else if(strcasecmp(prop.u.atom, "semibold") == 0)
310            return 600;
311        else if(strcasecmp(prop.u.atom, "bold") == 0)
312            return 700;
313        else if(strcasecmp(prop.u.atom, "extrabold") == 0)
314            return 800;
315        else if(strcasecmp(prop.u.atom, "black") == 0)
316            return 900;
317        else
318            return 400;
319    } else
320        return 400;             /* for now */
321}
322
323int
324faceWidth(FT_Face face)
325{
326    int rc;
327    BDF_PropertyRec prop;
328    rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop);
329    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
330        if(strcasecmp(prop.u.atom, "ultracondensed") == 0)
331            return 1;
332        else if(strcasecmp(prop.u.atom, "extracondensed") == 0)
333            return 2;
334        else if(strcasecmp(prop.u.atom, "condensed") == 0)
335            return 3;
336        else if(strcasecmp(prop.u.atom, "semicondensed") == 0)
337            return 4;
338        else if(strcasecmp(prop.u.atom, "normal") == 0)
339            return 5;
340        else if(strcasecmp(prop.u.atom, "semiexpanded") == 0)
341            return 6;
342        else if(strcasecmp(prop.u.atom, "expanded") == 0)
343            return 7;
344        else if(strcasecmp(prop.u.atom, "extraexpanded") == 0)
345            return 8;
346        else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0)
347            return 9;
348        else
349            return 5;
350    } else
351        return 5;               /* for now */
352}
353
354int
355faceItalicAngle(FT_Face face)
356{
357    int rc;
358    BDF_PropertyRec prop;
359
360    rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop);
361    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) {
362        return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64);
363    }
364
365    rc = FT_Get_BDF_Property(face, "SLANT", &prop);
366    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
367        if(strcasecmp(prop.u.atom, "i") == 0 ||
368           strcasecmp(prop.u.atom, "s") == 0)
369            return -30 * TWO_SIXTEENTH;
370        else
371            return 0;
372    } else
373        return 0;               /* for now */
374}
375
376int
377faceFlags(FT_Face face)
378{
379    int flags = 0;
380    BDF_PropertyRec prop;
381    int rc;
382
383    if(faceWeight(face) >= 650)
384        flags |= FACE_BOLD;
385    rc = FT_Get_BDF_Property(face, "SLANT", &prop);
386    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
387        if(strcasecmp(prop.u.atom, "i") == 0 ||
388           strcasecmp(prop.u.atom, "s") == 0)
389            flags |= FACE_ITALIC;
390    }
391    return flags;
392}
393
394int
395faceIntProp(FT_Face face, const char *name)
396{
397    int rc;
398    BDF_PropertyRec prop;
399
400    rc = FT_Get_BDF_Property(face, name, &prop);
401    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER)
402	return prop.u.integer;
403    else
404	return UNDEF;
405}
406
407char *
408faceStringProp(FT_Face face, const char *name)
409{
410    int rc;
411    BDF_PropertyRec prop;
412    char *buf = NULL;
413
414    rc = FT_Get_BDF_Property(face, name, &prop);
415    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
416	buf = sprintf_alloc("%s", prop.u.atom ? prop.u.atom : "");
417	if(buf == NULL) {
418	    perror("sprintf_alloc failed");
419	    exit(1);
420	}
421    }
422    return buf;
423}
424
425char *
426faceEncoding(FT_Face face)
427{
428    BDF_PropertyRec p1, p2;
429    int rc;
430
431    rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1);
432    if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM)
433        return NULL;
434    rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2);
435    if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM)
436        return NULL;
437    if(!(p1.u.atom && p2.u.atom))
438        return NULL;
439
440    return sprintf_alloc("%s-%s", p1.u.atom, p2.u.atom);
441}
442
443int
444degreesToFraction(int deg, int *num, int *den)
445{
446    double n, d;
447    double rad, val;
448    int i;
449
450    if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH))
451        goto fail;
452
453    rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI;
454
455    n = sin(-rad);
456    d = cos(rad);
457
458    if(d < 0.001)
459        goto fail;
460
461    val = atan2(n, d);
462    /* There must be a cleaner way */
463    for(i = 1; i < 10000; i++) {
464        if((int)(d * i) != 0.0 &&
465           fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) {
466            *num = (int)ROUND(n * i);
467            *den = (int)ROUND(d * i);
468            return 0;
469        }
470    }
471
472 fail:
473    *den = 1;
474    *num = 0;
475    return -1;
476}
477
478