util.c revision ea148d1d
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 < 0) return -1;
217
218    current = time(NULL);
219    if(current < 0)
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            return makeName("UNKN");
285    }
286    /* For now */
287    return makeName("UNKN");
288}
289
290
291int
292faceWeight(FT_Face face)
293{
294    int rc;
295    BDF_PropertyRec prop;
296    rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop);
297    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
298        if(strcasecmp(prop.u.atom, "thin") == 0)
299            return 100;
300        else if(strcasecmp(prop.u.atom, "extralight") == 0)
301            return 200;
302        else if(strcasecmp(prop.u.atom, "light") == 0)
303            return 300;
304        else if(strcasecmp(prop.u.atom, "medium") == 0)
305            return 500;
306        else if(strcasecmp(prop.u.atom, "semibold") == 0)
307            return 600;
308        else if(strcasecmp(prop.u.atom, "bold") == 0)
309            return 700;
310        else if(strcasecmp(prop.u.atom, "extrabold") == 0)
311            return 800;
312        else if(strcasecmp(prop.u.atom, "black") == 0)
313            return 900;
314        else
315            return 500;
316    } else
317        return 500;             /* for now */
318}
319
320int
321faceWidth(FT_Face face)
322{
323    int rc;
324    BDF_PropertyRec prop;
325    rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop);
326    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
327        if(strcasecmp(prop.u.atom, "ultracondensed") == 0)
328            return 1;
329        else if(strcasecmp(prop.u.atom, "extracondensed") == 0)
330            return 2;
331        else if(strcasecmp(prop.u.atom, "condensed") == 0)
332            return 3;
333        else if(strcasecmp(prop.u.atom, "semicondensed") == 0)
334            return 4;
335        else if(strcasecmp(prop.u.atom, "normal") == 0)
336            return 5;
337        else if(strcasecmp(prop.u.atom, "semiexpanded") == 0)
338            return 6;
339        else if(strcasecmp(prop.u.atom, "expanded") == 0)
340            return 7;
341        else if(strcasecmp(prop.u.atom, "extraexpanded") == 0)
342            return 8;
343        else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0)
344            return 9;
345        else
346            return 5;
347    } else
348        return 5;               /* for now */
349}
350
351int
352faceItalicAngle(FT_Face face)
353{
354    int rc;
355    BDF_PropertyRec prop;
356
357    rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop);
358    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) {
359        return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64);
360    }
361
362    rc = FT_Get_BDF_Property(face, "SLANT", &prop);
363    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
364        if(strcasecmp(prop.u.atom, "i") == 0 ||
365           strcasecmp(prop.u.atom, "s") == 0)
366            return -30 * TWO_SIXTEENTH;
367        else
368            return 0;
369    } else
370        return 0;               /* for now */
371}
372
373int
374faceFlags(FT_Face face)
375{
376    int flags = 0;
377    BDF_PropertyRec prop;
378    int rc;
379
380    if(faceWeight(face) >= 650)
381        flags |= FACE_BOLD;
382    rc = FT_Get_BDF_Property(face, "SLANT", &prop);
383    if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM && prop.u.atom) {
384        if(strcasecmp(prop.u.atom, "i") == 0 ||
385           strcasecmp(prop.u.atom, "s") == 0)
386            flags |= FACE_ITALIC;
387    }
388    return flags;
389}
390
391char *
392faceEncoding(FT_Face face)
393{
394    BDF_PropertyRec p1, p2;
395    int rc;
396
397    rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1);
398    if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM)
399        return NULL;
400    rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2);
401    if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM)
402        return NULL;
403    if(!(p1.u.atom && p2.u.atom))
404        return NULL;
405
406    return sprintf_alloc("%s-%s", p1.u.atom, p2.u.atom);
407}
408
409int
410degreesToFraction(int deg, int *num, int *den)
411{
412    double n, d;
413    double rad, val;
414    int i;
415
416    if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH))
417        goto fail;
418
419    rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI;
420
421    n = sin(-rad);
422    d = cos(rad);
423
424    if(d < 0.001)
425        goto fail;
426
427    val = atan2(n, d);
428    /* There must be a cleaner way */
429    for(i = 1; i < 10000; i++) {
430        if((int)(d * i) != 0.0 &&
431           fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) {
432            *num = (int)ROUND(n * i);
433            *den = (int)ROUND(d * i);
434            return 0;
435        }
436    }
437
438 fail:
439    *den = 1;
440    *num = 0;
441    return -1;
442}
443
444