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