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