util.c revision 43f32c10
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 "fonttosfnt.h"
41
42#ifdef NEED_SNPRINTF
43#undef SCOPE
44#define SCOPE static
45#include "snprintf.c"
46#endif
47
48#ifdef __GLIBC__
49#define HAVE_TIMEGM
50#define HAVE_TM_GMTOFF
51#endif
52
53#ifdef BSD
54#define HAVE_TM_GMTOFF
55#define GMTOFFMEMBER tm_gmtoff
56#endif
57
58#ifdef __SCO__
59#define HAVE_TM_GMTOFF
60#define GMTOFFMEMBER tm_tzadj
61#endif
62
63/* That's in POSIX */
64#define HAVE_TZSET
65
66#ifdef NEED_SETENV
67extern int setenv(const char *name, const char *value, int overwrite);
68extern void unsetenv(const char *name);
69#endif
70
71char*
72sprintf_alloc(char *f, ...)
73{
74    char *s;
75    va_list args;
76    va_start(args, f);
77    s = vsprintf_alloc(f, args);
78    va_end(args);
79    return s;
80}
81
82#if HAVE_VASPRINTF
83char*
84vsprintf_alloc(char *f, va_list args)
85{
86    char *r;
87    int rc;
88
89    rc = vasprintf(&r, f, args);
90    if(rc < 0)
91        return NULL;
92    return r;
93}
94#else
95char*
96vsprintf_alloc(char *f, va_list args)
97{
98    int n, size = 12;
99    char *string;
100    va_list args_copy;
101
102    while(1) {
103        if(size > 4096)
104            return NULL;
105        string = malloc(size);
106        if(!string)
107            return NULL;
108
109#if HAVE_DECL_VA_COPY
110        va_copy(args_copy, args);
111        n = vsnprintf(string, size, f, args_copy);
112#else
113        n = vsnprintf(string, size, f, args);
114#endif
115        if(n >= 0 && n < size)
116            return string;
117        else if(n >= size)
118            size = n + 1;
119        else
120            size = size * 3 / 2 + 1;
121        free(string);
122    }
123    /* NOTREACHED */
124}
125#endif
126
127/* Build a UTF-16 string from a Latin-1 string.
128   Result is not NUL-terminated. */
129char *
130makeUTF16(char *string)
131{
132    int i;
133    int n = strlen(string);
134    char *value = malloc(2 * n);
135    if(!value)
136        return NULL;
137    for(i = 0; i < n; i++) {
138        value[2 * i] = '\0';
139        value[2 * i + 1] = string[i];
140    }
141    return value;
142}
143
144unsigned
145makeName(char *s)
146{
147    return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
148}
149
150/* Like mktime(3), but UTC rather than local time */
151#if defined(HAVE_TIMEGM)
152static time_t
153mktime_gmt(struct tm *tm)
154{
155    return timegm(tm);
156}
157#elif defined(HAVE_TM_GMTOFF)
158static time_t
159mktime_gmt(struct tm *tm)
160{
161    time_t t;
162    struct tm *ltm;
163
164    t = mktime(tm);
165    if(t < 0)
166        return -1;
167    ltm = localtime(&t);
168    if(ltm == NULL)
169        return -1;
170    return t + ltm->GMTOFFMEMBER;
171}
172#elif defined(HAVE_TZSET)
173/* Taken from the Linux timegm(3) man page */
174static time_t
175mktime_gmt(struct tm *tm)
176{
177    time_t t;
178    char *tz;
179
180    tz = getenv("TZ");
181    setenv("TZ", "", 1);
182    tzset();
183    t = mktime(tm);
184    if(tz)
185        setenv("TZ", tz, 1);
186    else
187        unsetenv("TZ");
188    tzset();
189    return t;
190}
191#else
192#error no mktime_gmt implementation on this platform
193#endif
194
195/* Return the current time as a signed 64-bit number of seconds since
196   midnight, 1 January 1904.  This is apparently when the Macintosh
197   was designed. */
198int
199macTime(int *hi, unsigned *lo)
200{
201    unsigned long diff;		/* Not time_t */
202    time_t macEpoch, current;
203    struct tm tm;
204    tm.tm_sec = 0;
205    tm.tm_min = 0;
206    tm.tm_hour = 0;
207    tm.tm_mday = 1;
208    tm.tm_mon = 1;
209    tm.tm_year = 4;
210    tm.tm_isdst = -1;
211
212    macEpoch = mktime_gmt(&tm);
213    if(macEpoch < 0) return -1;
214
215    current = time(NULL);
216    if(current < 0)
217        return -1;
218
219    if(current < macEpoch) {
220        errno = EINVAL;
221        return -1;
222    }
223
224    diff = current - macEpoch;
225#if INT_MAX == LONG_MAX
226    *hi = 0;
227#else
228    *hi = diff >> 32;
229#endif
230    *lo = diff & 0xFFFFFFFF;
231    return 0;
232}
233
234unsigned
235faceFoundry(FT_Face face)
236{
237    int rc;
238    BDF_PropertyRec prop;
239
240    rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
241    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
242        if(strcasecmp(prop.u.atom, "adobe") == 0)
243            return makeName("ADBE");
244        else if(strcasecmp(prop.u.atom, "agfa") == 0)
245            return makeName("AGFA");
246        else if(strcasecmp(prop.u.atom, "altsys") == 0)
247            return makeName("ALTS");
248        else if(strcasecmp(prop.u.atom, "apple") == 0)
249            return makeName("APPL");
250        else if(strcasecmp(prop.u.atom, "arphic") == 0)
251            return makeName("ARPH");
252        else if(strcasecmp(prop.u.atom, "alltype") == 0)
253            return makeName("ATEC");
254        else if(strcasecmp(prop.u.atom, "b&h") == 0)
255            return makeName("B&H ");
256        else if(strcasecmp(prop.u.atom, "bitstream") == 0)
257            return makeName("BITS");
258        else if(strcasecmp(prop.u.atom, "dynalab") == 0)
259            return makeName("DYNA");
260        else if(strcasecmp(prop.u.atom, "ibm") == 0)
261            return makeName("IBM ");
262        else if(strcasecmp(prop.u.atom, "itc") == 0)
263            return makeName("ITC ");
264        else if(strcasecmp(prop.u.atom, "interleaf") == 0)
265            return makeName("LEAF");
266        else if(strcasecmp(prop.u.atom, "impress") == 0)
267            return makeName("IMPR");
268        else if(strcasecmp(prop.u.atom, "larabiefonts") == 0)
269            return makeName("LARA");
270        else if(strcasecmp(prop.u.atom, "linotype") == 0)
271            return makeName("LINO");
272        else if(strcasecmp(prop.u.atom, "monotype") == 0)
273            return makeName("MT  ");
274        else if(strcasecmp(prop.u.atom, "microsoft") == 0)
275            return makeName("MS  ");
276        else if(strcasecmp(prop.u.atom, "urw") == 0)
277            return makeName("URW ");
278        else if(strcasecmp(prop.u.atom, "y&y") == 0)
279            return makeName("Y&Y ");
280        else
281            return makeName("UNKN");
282    }
283    /* For now */
284    return makeName("UNKN");
285}
286
287
288int
289faceWeight(FT_Face face)
290{
291    int rc;
292    BDF_PropertyRec prop;
293    rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop);
294    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
295        if(strcasecmp(prop.u.atom, "thin") == 0)
296            return 100;
297        else if(strcasecmp(prop.u.atom, "extralight") == 0)
298            return 200;
299        else if(strcasecmp(prop.u.atom, "light") == 0)
300            return 300;
301        else if(strcasecmp(prop.u.atom, "medium") == 0)
302            return 500;
303        else if(strcasecmp(prop.u.atom, "semibold") == 0)
304            return 600;
305        else if(strcasecmp(prop.u.atom, "bold") == 0)
306            return 700;
307        else if(strcasecmp(prop.u.atom, "extrabold") == 0)
308            return 800;
309        else if(strcasecmp(prop.u.atom, "black") == 0)
310            return 900;
311        else
312            return 500;
313    } else
314        return 500;             /* for now */
315}
316
317int
318faceWidth(FT_Face face)
319{
320    int rc;
321    BDF_PropertyRec prop;
322    rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop);
323    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
324        if(strcasecmp(prop.u.atom, "ultracondensed") == 0)
325            return 1;
326        else if(strcasecmp(prop.u.atom, "extracondensed") == 0)
327            return 2;
328        else if(strcasecmp(prop.u.atom, "condensed") == 0)
329            return 3;
330        else if(strcasecmp(prop.u.atom, "semicondensed") == 0)
331            return 4;
332        else if(strcasecmp(prop.u.atom, "normal") == 0)
333            return 5;
334        else if(strcasecmp(prop.u.atom, "semiexpanded") == 0)
335            return 6;
336        else if(strcasecmp(prop.u.atom, "expanded") == 0)
337            return 7;
338        else if(strcasecmp(prop.u.atom, "extraexpanded") == 0)
339            return 8;
340        else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0)
341            return 9;
342        else
343            return 5;
344    } else
345        return 5;               /* for now */
346}
347
348int
349faceItalicAngle(FT_Face face)
350{
351    int rc;
352    BDF_PropertyRec prop;
353
354    rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop);
355    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) {
356        return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64);
357    }
358
359    rc = FT_Get_BDF_Property(face, "SLANT", &prop);
360    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
361        if(strcasecmp(prop.u.atom, "i") == 0 ||
362           strcasecmp(prop.u.atom, "s") == 0)
363            return -30 * TWO_SIXTEENTH;
364        else
365            return 0;
366    } else
367        return 0;               /* for now */
368}
369
370int
371faceFlags(FT_Face face)
372{
373    int flags = 0;
374    BDF_PropertyRec prop;
375    int rc;
376
377    if(faceWeight(face) >= 650)
378        flags |= FACE_BOLD;
379    rc = FT_Get_BDF_Property(face, "SLANT", &prop);
380    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
381        if(strcasecmp(prop.u.atom, "i") == 0 ||
382           strcasecmp(prop.u.atom, "s") == 0)
383            flags |= FACE_ITALIC;
384    }
385    return flags;
386}
387
388char *
389faceEncoding(FT_Face face)
390{
391    BDF_PropertyRec p1, p2;
392    int rc;
393
394    rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1);
395    if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM)
396        return NULL;
397    rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2);
398    if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM)
399        return NULL;
400
401    return sprintf_alloc("%s-%s", p1.u.atom, p2.u.atom);
402}
403
404int
405degreesToFraction(int deg, int *num, int *den)
406{
407    double n, d;
408    double rad, val;
409    int i;
410
411    if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH))
412        goto fail;
413
414    rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI;
415
416    n = sin(-rad);
417    d = cos(rad);
418
419    if(d < 0.001)
420        goto fail;
421
422    val = atan2(n, d);
423    /* There must be a cleaner way */
424    for(i = 1; i < 10000; i++) {
425        if((int)(d * i) != 0.0 &&
426           fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) {
427            *num = (int)ROUND(n * i);
428            *den = (int)ROUND(d * i);
429            return 0;
430        }
431    }
432
433 fail:
434    *den = 1;
435    *num = 0;
436    return -1;
437}
438
439