util.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. Copyright (c) 2002-2003 by Juliusz Chroboczek
  3. Permission is hereby granted, free of charge, to any person obtaining a copy
  4. of this software and associated documentation files (the "Software"), to deal
  5. in the Software without restriction, including without limitation the rights
  6. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. copies of the Software, and to permit persons to whom the Software is
  8. furnished to do so, subject to the following conditions:
  9. The above copyright notice and this permission notice shall be included in
  10. all copies or substantial portions of the Software.
  11. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  17. THE SOFTWARE.
  18. */
  19. /* $XdotOrg: xc/programs/fonttosfnt/util.c,v 1.11 2003/12/19 02:16:36 dawes Exp $ */
  20. /* $XFree86: xc/programs/fonttosfnt/util.c,v 1.10 2003/12/19 02:05:39 dawes Exp $ */
  21. #include <time.h>
  22. #include <string.h>
  23. #include <errno.h>
  24. #include <stdlib.h>
  25. #ifndef __UNIXOS2__
  26. # include <math.h>
  27. #else
  28. # include <float.h>
  29. #endif
  30. #include <stdarg.h>
  31. #include <ft2build.h>
  32. #include FT_FREETYPE_H
  33. #include FT_BDF_H
  34. #include "X11/Xos.h"
  35. #include "fonttosfnt.h"
  36. #ifdef NEED_SNPRINTF
  37. #undef SCOPE
  38. #define SCOPE static
  39. #include "snprintf.c"
  40. #endif
  41. #ifdef __GLIBC__
  42. #define HAVE_TIMEGM
  43. #define HAVE_TM_GMTOFF
  44. #endif
  45. #ifdef BSD
  46. #define HAVE_TM_GMTOFF
  47. #define GMTOFFMEMBER tm_gmtoff
  48. #endif
  49. #ifdef __SCO__
  50. #define HAVE_TM_GMTOFF
  51. #define GMTOFFMEMBER tm_tzadj
  52. #endif
  53. /* That's in POSIX */
  54. #define HAVE_TZSET
  55. #ifdef NEED_SETENV
  56. extern int setenv(const char *name, const char *value, int overwrite);
  57. extern void unsetenv(const char *name);
  58. #endif
  59. char*
  60. sprintf_alloc(char *f, ...)
  61. {
  62. char *s;
  63. va_list args;
  64. va_start(args, f);
  65. s = vsprintf_alloc(f, args);
  66. va_end(args);
  67. return s;
  68. }
  69. #if HAVE_VASPRINTF
  70. char*
  71. vsprintf_alloc(char *f, va_list args)
  72. {
  73. char *r;
  74. int rc;
  75. rc = vasprintf(&r, f, args);
  76. if(rc < 0)
  77. return NULL;
  78. return r;
  79. }
  80. #else
  81. char*
  82. vsprintf_alloc(char *f, va_list args)
  83. {
  84. int n, size = 12;
  85. char *string;
  86. va_list args_copy;
  87. while(1) {
  88. if(size > 4096)
  89. return NULL;
  90. string = malloc(size);
  91. if(!string)
  92. return NULL;
  93. #if HAVE_DECL_VA_COPY
  94. va_copy(args_copy, args);
  95. n = vsnprintf(string, size, f, args_copy);
  96. #else
  97. n = vsnprintf(string, size, f, args);
  98. #endif
  99. if(n >= 0 && n < size)
  100. return string;
  101. else if(n >= size)
  102. size = n + 1;
  103. else
  104. size = size * 3 / 2 + 1;
  105. free(string);
  106. }
  107. /* NOTREACHED */
  108. }
  109. #endif
  110. /* Build a UTF-16 string from a Latin-1 string.
  111. Result is not NUL-terminated. */
  112. char *
  113. makeUTF16(char *string)
  114. {
  115. int i;
  116. int n = strlen(string);
  117. char *value = malloc(2 * n);
  118. if(!value)
  119. return NULL;
  120. for(i = 0; i < n; i++) {
  121. value[2 * i] = '\0';
  122. value[2 * i + 1] = string[i];
  123. }
  124. return value;
  125. }
  126. unsigned
  127. makeName(char *s)
  128. {
  129. return s[0] << 24 | s[1] << 16 | s[2] << 8 | s[3];
  130. }
  131. /* Like mktime(3), but UTC rather than local time */
  132. #if defined(HAVE_TIMEGM)
  133. static time_t
  134. mktime_gmt(struct tm *tm)
  135. {
  136. return timegm(tm);
  137. }
  138. #elif defined(HAVE_TM_GMTOFF)
  139. static time_t
  140. mktime_gmt(struct tm *tm)
  141. {
  142. time_t t;
  143. struct tm *ltm;
  144. t = mktime(tm);
  145. if(t < 0)
  146. return -1;
  147. ltm = localtime(&t);
  148. if(ltm == NULL)
  149. return -1;
  150. return t + ltm->GMTOFFMEMBER;
  151. }
  152. #elif defined(HAVE_TZSET)
  153. /* Taken from the Linux timegm(3) man page */
  154. static time_t
  155. mktime_gmt(struct tm *tm)
  156. {
  157. time_t t;
  158. char *tz;
  159. tz = getenv("TZ");
  160. setenv("TZ", "", 1);
  161. tzset();
  162. t = mktime(tm);
  163. if(tz)
  164. setenv("TZ", tz, 1);
  165. else
  166. unsetenv("TZ");
  167. tzset();
  168. return t;
  169. }
  170. #else
  171. #error no mktime_gmt implementation on this platform
  172. #endif
  173. /* Return the current time as a signed 64-bit number of seconds since
  174. midnight, 1 January 1904. This is apparently when the Macintosh
  175. was designed. */
  176. int
  177. macTime(int *hi, unsigned *lo)
  178. {
  179. unsigned long diff; /* Not time_t */
  180. time_t macEpoch, current;
  181. struct tm tm;
  182. tm.tm_sec = 0;
  183. tm.tm_min = 0;
  184. tm.tm_hour = 0;
  185. tm.tm_mday = 1;
  186. tm.tm_mon = 1;
  187. tm.tm_year = 4;
  188. tm.tm_isdst = -1;
  189. macEpoch = mktime_gmt(&tm);
  190. if(macEpoch < 0) return -1;
  191. current = time(NULL);
  192. if(current < 0)
  193. return -1;
  194. if(current < macEpoch) {
  195. errno = EINVAL;
  196. return -1;
  197. }
  198. diff = current - macEpoch;
  199. #if INT_MAX == LONG_MAX
  200. *hi = 0;
  201. #else
  202. *hi = diff >> 32;
  203. #endif
  204. *lo = diff & 0xFFFFFFFF;
  205. return 0;
  206. }
  207. unsigned
  208. faceFoundry(FT_Face face)
  209. {
  210. int rc;
  211. BDF_PropertyRec prop;
  212. rc = FT_Get_BDF_Property(face, "FOUNDRY", &prop);
  213. if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
  214. if(strcasecmp(prop.u.atom, "adobe") == 0)
  215. return makeName("ADBE");
  216. else if(strcasecmp(prop.u.atom, "agfa") == 0)
  217. return makeName("AGFA");
  218. else if(strcasecmp(prop.u.atom, "altsys") == 0)
  219. return makeName("ALTS");
  220. else if(strcasecmp(prop.u.atom, "apple") == 0)
  221. return makeName("APPL");
  222. else if(strcasecmp(prop.u.atom, "arphic") == 0)
  223. return makeName("ARPH");
  224. else if(strcasecmp(prop.u.atom, "alltype") == 0)
  225. return makeName("ATEC");
  226. else if(strcasecmp(prop.u.atom, "b&h") == 0)
  227. return makeName("B&H ");
  228. else if(strcasecmp(prop.u.atom, "bitstream") == 0)
  229. return makeName("BITS");
  230. else if(strcasecmp(prop.u.atom, "dynalab") == 0)
  231. return makeName("DYNA");
  232. else if(strcasecmp(prop.u.atom, "ibm") == 0)
  233. return makeName("IBM ");
  234. else if(strcasecmp(prop.u.atom, "itc") == 0)
  235. return makeName("ITC ");
  236. else if(strcasecmp(prop.u.atom, "interleaf") == 0)
  237. return makeName("LEAF");
  238. else if(strcasecmp(prop.u.atom, "impress") == 0)
  239. return makeName("IMPR");
  240. else if(strcasecmp(prop.u.atom, "larabiefonts") == 0)
  241. return makeName("LARA");
  242. else if(strcasecmp(prop.u.atom, "linotype") == 0)
  243. return makeName("LINO");
  244. else if(strcasecmp(prop.u.atom, "monotype") == 0)
  245. return makeName("MT ");
  246. else if(strcasecmp(prop.u.atom, "microsoft") == 0)
  247. return makeName("MS ");
  248. else if(strcasecmp(prop.u.atom, "urw") == 0)
  249. return makeName("URW ");
  250. else if(strcasecmp(prop.u.atom, "y&y") == 0)
  251. return makeName("Y&Y ");
  252. else
  253. return makeName("UNKN");
  254. }
  255. /* For now */
  256. return makeName("UNKN");
  257. }
  258. int
  259. faceWeight(FT_Face face)
  260. {
  261. int rc;
  262. BDF_PropertyRec prop;
  263. rc = FT_Get_BDF_Property(face, "WEIGHT_NAME", &prop);
  264. if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
  265. if(strcasecmp(prop.u.atom, "thin") == 0)
  266. return 100;
  267. else if(strcasecmp(prop.u.atom, "extralight") == 0)
  268. return 200;
  269. else if(strcasecmp(prop.u.atom, "light") == 0)
  270. return 300;
  271. else if(strcasecmp(prop.u.atom, "medium") == 0)
  272. return 500;
  273. else if(strcasecmp(prop.u.atom, "semibold") == 0)
  274. return 600;
  275. else if(strcasecmp(prop.u.atom, "bold") == 0)
  276. return 700;
  277. else if(strcasecmp(prop.u.atom, "extrabold") == 0)
  278. return 800;
  279. else if(strcasecmp(prop.u.atom, "black") == 0)
  280. return 900;
  281. else
  282. return 500;
  283. } else
  284. return 500; /* for now */
  285. }
  286. int
  287. faceWidth(FT_Face face)
  288. {
  289. int rc;
  290. BDF_PropertyRec prop;
  291. rc = FT_Get_BDF_Property(face, "SETWIDTH_NAME", &prop);
  292. if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
  293. if(strcasecmp(prop.u.atom, "ultracondensed") == 0)
  294. return 1;
  295. else if(strcasecmp(prop.u.atom, "extracondensed") == 0)
  296. return 2;
  297. else if(strcasecmp(prop.u.atom, "condensed") == 0)
  298. return 3;
  299. else if(strcasecmp(prop.u.atom, "semicondensed") == 0)
  300. return 4;
  301. else if(strcasecmp(prop.u.atom, "normal") == 0)
  302. return 5;
  303. else if(strcasecmp(prop.u.atom, "semiexpanded") == 0)
  304. return 6;
  305. else if(strcasecmp(prop.u.atom, "expanded") == 0)
  306. return 7;
  307. else if(strcasecmp(prop.u.atom, "extraexpanded") == 0)
  308. return 8;
  309. else if(strcasecmp(prop.u.atom, "ultraexpanded") == 0)
  310. return 9;
  311. else
  312. return 5;
  313. } else
  314. return 5; /* for now */
  315. }
  316. int
  317. faceItalicAngle(FT_Face face)
  318. {
  319. int rc;
  320. BDF_PropertyRec prop;
  321. rc = FT_Get_BDF_Property(face, "ITALIC_ANGLE", &prop);
  322. if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_INTEGER) {
  323. return (prop.u.integer - 64 * 90) * (TWO_SIXTEENTH / 64);
  324. }
  325. rc = FT_Get_BDF_Property(face, "SLANT", &prop);
  326. if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
  327. if(strcasecmp(prop.u.atom, "i") == 0 ||
  328. strcasecmp(prop.u.atom, "s") == 0)
  329. return -30 * TWO_SIXTEENTH;
  330. else
  331. return 0;
  332. } else
  333. return 0; /* for now */
  334. }
  335. int
  336. faceFlags(FT_Face face)
  337. {
  338. int flags = 0;
  339. BDF_PropertyRec prop;
  340. int rc;
  341. if(faceWeight(face) >= 650)
  342. flags |= FACE_BOLD;
  343. rc = FT_Get_BDF_Property(face, "SLANT", &prop);
  344. if(rc == 0 && prop.type == BDF_PROPERTY_TYPE_ATOM) {
  345. if(strcasecmp(prop.u.atom, "i") == 0 ||
  346. strcasecmp(prop.u.atom, "s") == 0)
  347. flags |= FACE_ITALIC;
  348. }
  349. return flags;
  350. }
  351. char *
  352. faceEncoding(FT_Face face)
  353. {
  354. BDF_PropertyRec p1, p2;
  355. int rc;
  356. rc = FT_Get_BDF_Property(face, "CHARSET_REGISTRY", &p1);
  357. if(rc != 0 || p1.type != BDF_PROPERTY_TYPE_ATOM)
  358. return NULL;
  359. rc = FT_Get_BDF_Property(face, "CHARSET_ENCODING", &p2);
  360. if(rc != 0 || p2.type != BDF_PROPERTY_TYPE_ATOM)
  361. return NULL;
  362. return sprintf_alloc("%s-%s", p1.u.atom, p2.u.atom);
  363. }
  364. int
  365. degreesToFraction(int deg, int *num, int *den)
  366. {
  367. double n, d;
  368. double rad, val;
  369. int i;
  370. if(deg <= -(60 * TWO_SIXTEENTH) || deg >= (60 * TWO_SIXTEENTH))
  371. goto fail;
  372. rad = (((double)deg) / TWO_SIXTEENTH) / 180.0 * M_PI;
  373. n = sin(-rad);
  374. d = cos(rad);
  375. if(d < 0.001)
  376. goto fail;
  377. val = atan2(n, d);
  378. /* There must be a cleaner way */
  379. for(i = 1; i < 10000; i++) {
  380. if((int)(d * i) != 0.0 &&
  381. fabs(atan2(ROUND(n * i), ROUND(d * i)) - val) < 0.05) {
  382. *num = (int)ROUND(n * i);
  383. *den = (int)ROUND(d * i);
  384. return 0;
  385. }
  386. }
  387. fail:
  388. *den = 1;
  389. *num = 0;
  390. return -1;
  391. }