util.c revision 6ef05171
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(const 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(const 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(const 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(const 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(const 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