1 /****************************************************************************\
2  Part of the XeTeX typesetting system
3  Copyright (c) 1994-2008 by SIL International
4  Copyright (c) 2009, 2011 by Jonathan Kew
5  Copyright (c) 2012-2015 by Khaled Hosny
6  Copyright (c) 2012, 2013 by Jiang Jiang
7 
8  SIL Author(s): Jonathan Kew
9 
10 Permission is hereby granted, free of charge, to any person obtaining
11 a copy of this software and associated documentation files (the
12 "Software"), to deal in the Software without restriction, including
13 without limitation the rights to use, copy, modify, merge, publish,
14 distribute, sublicense, and/or sell copies of the Software, and to
15 permit persons to whom the Software is furnished to do so, subject to
16 the following conditions:
17 
18 The above copyright notice and this permission notice shall be
19 included in all copies or substantial portions of the Software.
20 
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
25 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
26 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 
29 Except as contained in this notice, the name of the copyright holders
30 shall not be used in advertising or otherwise to promote the sale,
31 use or other dealings in this Software without prior written
32 authorization from the copyright holders.
33 \****************************************************************************/
34 
35 /* XeTeX_ext.c
36  * additional plain C extensions for XeTeX - mostly platform-neutral
37  */
38 
39 #include <w2c/config.h>
40 
41 #include <poppler-config.h>
42 #include <png.h>
43 #include <zlib.h>
44 #include <graphite2/Font.h>
45 
46 #ifdef _MSC_VER
47 #undef timezone
48 #endif
49 
50 #include <time.h> /* For `struct tm'.  */
51 #if defined (HAVE_SYS_TIME_H)
52 #include <sys/time.h>
53 #elif defined (HAVE_SYS_TIMEB_H)
54 #include <sys/timeb.h>
55 #endif
56 
57 #define EXTERN extern
58 #include "xetexd.h"
59 
60 #include "XeTeX_ext.h"
61 
62 #include <teckit/TECkit_Engine.h>
63 
64 #include <kpathsea/c-ctype.h>
65 #include <kpathsea/line.h>
66 #include <kpathsea/readable.h>
67 #include <kpathsea/variable.h>
68 #include <kpathsea/absolute.h>
69 #if defined(WIN32)
70 #include <kpathsea/concatn.h>
71 #endif
72 
73 #include <math.h> /* for fabs() */
74 
75 #if defined(__STDC__)
76 #include <locale.h>
77 #endif
78 
79 #include <signal.h> /* Catch interrupts.  */
80 
81 #include "XeTeXLayoutInterface.h"
82 
83 #include "XeTeXswap.h"
84 
85 #include <unicode/ubidi.h>
86 #include <unicode/ubrk.h>
87 #include <unicode/ucnv.h>
88 
89 #include <assert.h>
90 
91 /* for reading input files, we don't need the default locking routines
92    as xetex is a single-threaded program */
93 #ifdef WIN32
94 #ifdef __MINGW32__
95 /* MinGW (both 32- and 64-bit) has problems with _getc_nolock() and/or _ungetc_nolock() */
96 #define GETC(f)      getc(f)
97 #define UNGETC(c,f)  ungetc(c,f)
98 #else
99 #define GETC(f)      _getc_nolock(f)
100 #define UNGETC(c,f)  _ungetc_nolock(c,f)
101 #endif
102 #else
103 #define GETC(f)      getc_unlocked(f)
104 #define UNGETC(c,f)  ungetc(c,f)
105 #endif
106 
107 /* tables/values used in UTF-8 interpretation -
108    code is based on ConvertUTF.[ch] sample code
109    published by the Unicode consortium */
110 const uint32_t
111 offsetsFromUTF8[6] =    {
112     0x00000000UL,
113     0x00003080UL,
114     0x000E2080UL,
115     0x03C82080UL,
116     0xFA082080UL,
117     0x82082080UL
118 };
119 
120 const uint8_t
121 bytesFromUTF8[256] = {
122     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
123     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
124     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
125     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
126     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
127     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
129     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
130 };
131 
132 const uint8_t
133 firstByteMark[7] = {
134     0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC
135 };
136 
137 const int halfShift                 = 10;
138 const uint32_t halfBase             = 0x0010000UL;
139 const uint32_t halfMask             = 0x3FFUL;
140 const uint32_t kSurrogateHighStart  = 0xD800UL;
141 const uint32_t kSurrogateHighEnd        = 0xDBFFUL;
142 const uint32_t kSurrogateLowStart       = 0xDC00UL;
143 const uint32_t kSurrogateLowEnd     = 0xDFFFUL;
144 const uint32_t byteMask             = 0x000000BFUL;
145 const uint32_t byteMark             = 0x00000080UL;
146 
147 
148 /* if the user specifies a paper size or output driver program */
149 const char *papersize;
150 const char *outputdriver = "xdvipdfmx -q -E"; /* default to portable xdvipdfmx driver */
151 
152 
initversionstring(char ** versions)153 void initversionstring(char **versions)
154 {
155 #ifndef XETEX_MAC
156     int fc_version = FcGetVersion();
157 #endif
158     FT_Int ftMajor, ftMinor, ftPatch;
159     int grMajor, grMinor, grBugfix;
160     UVersionInfo icuVersion;
161     char icu_version[U_MAX_VERSION_STRING_LENGTH] = "";
162 
163     const_string fmt =
164         "Compiled with ICU version %s; using %s\n"
165         "Compiled with zlib version %s; using %s\n"
166         "Compiled with FreeType2 version %d.%d.%d; using %d.%d.%d\n"
167         "Compiled with Graphite2 version %d.%d.%d; using %d.%d.%d\n"
168         "Compiled with HarfBuzz version %s; using %s\n"
169         "Compiled with libpng version %s; using %s\n"
170         "Compiled with poppler version %s\n"
171 #ifdef XETEX_MAC
172         "Using Mac OS X Core Text and Cocoa frameworks\n"
173 #else
174         "Compiled with fontconfig version %d.%d.%d; using %d.%d.%d\n"
175 #endif
176         ;
177 
178     int len = strlen(fmt)
179             + strlen(U_ICU_VERSION)
180             + strlen(icu_version)
181             + strlen(ZLIB_VERSION)
182             + strlen(zlib_version)
183             + strlen(HB_VERSION_STRING)
184             + strlen(hb_version_string())
185             + strlen(PNG_LIBPNG_VER_STRING)
186             + strlen(png_libpng_ver)
187             + strlen(POPPLER_VERSION)
188 #ifndef XETEX_MAC
189             + 6 * 3 /* for fontconfig version #s (won't really need 3 digits per field!) */
190 #endif
191             + 6 * 3 /* for graphite2 version #s (ditto) */
192             + 6 * 3; /* for freetype version #s (ditto) */
193 
194     *versions = (char *) xmalloc(len + 1);
195         /* len will be more than enough, because of the placeholder chars in fmt
196             that get replaced by the arguments */
197 
198     u_getVersion(icuVersion);
199     u_versionToString(icuVersion, icu_version);
200 
201     if (gFreeTypeLibrary == 0 && FT_Init_FreeType(&gFreeTypeLibrary) != 0) {
202         fprintf(stderr, "FreeType initialization failed!\n");
203         exit(9);
204     }
205     FT_Library_Version(gFreeTypeLibrary, &ftMajor, &ftMinor, &ftPatch);
206 
207     gr_engine_version(&grMajor, &grMinor, &grBugfix);
208 
209     (void)sprintf(*versions, fmt,
210         U_ICU_VERSION, icu_version,
211         ZLIB_VERSION, zlib_version,
212         FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH,
213         ftMajor, ftMinor, ftPatch,
214         GR2_VERSION_MAJOR, GR2_VERSION_MINOR, GR2_VERSION_BUGFIX,
215         grMajor, grMinor, grBugfix,
216         HB_VERSION_STRING, hb_version_string(),
217         PNG_LIBPNG_VER_STRING, png_libpng_ver, POPPLER_VERSION
218 #ifndef XETEX_MAC
219         ,
220         FC_VERSION / 10000, (FC_VERSION % 10000) / 100, FC_VERSION % 100,
221         fc_version / 10000, (fc_version % 10000) / 100, fc_version % 100
222 #endif
223         );
224 }
225 
226 
227 void
setinputfileencoding(UFILE * f,integer mode,integer encodingData)228 setinputfileencoding(UFILE* f, integer mode, integer encodingData)
229 {
230     if ((f->encodingMode == ICUMAPPING) && (f->conversionData != NULL))
231         ucnv_close((UConverter*)(f->conversionData));
232     f->conversionData = 0;
233 
234     switch (mode) {
235         case UTF8:
236         case UTF16BE:
237         case UTF16LE:
238         case RAW:
239             f->encodingMode = mode;
240             break;
241 
242         case ICUMAPPING:
243             {
244                 char* name = gettexstring(encodingData);
245                 UErrorCode err = U_ZERO_ERROR;
246                 UConverter* cnv = ucnv_open(name, &err);
247                 if (cnv == NULL) {
248                     begindiagnostic();
249                     printnl('E');
250                     printcstring("rror ");
251                     printint(err);
252                     printcstring(" creating Unicode converter for `");
253                     printcstring(name);
254                     printcstring("'; reading as raw bytes");
255                     enddiagnostic(1);
256                     f->encodingMode = RAW;
257                 } else {
258                     f->encodingMode = ICUMAPPING;
259                     f->conversionData = cnv;
260                 }
261                 free(name);
262             }
263             break;
264     }
265 }
266 
267 void
uclose(UFILE * f)268 uclose(UFILE* f)
269 {
270     if (f != 0) {
271         fclose(f->f);
272         if ((f->encodingMode == ICUMAPPING) && (f->conversionData != NULL))
273             ucnv_close((UConverter*)(f->conversionData));
274         free((void*)f);
275     }
276 }
277 
278 static void
buffer_overflow()279 buffer_overflow()
280 {
281     fprintf (stderr, "! Unable to read an entire line---bufsize=%u.\n",
282                              (unsigned) bufsize);
283     fputs ("Please increase buf_size in texmf.cnf.\n", stderr);
284     uexit (1);
285 }
286 
287 static void
conversion_error(int errcode)288 conversion_error(int errcode)
289 {
290     begindiagnostic();
291     printnl('U');
292     printcstring("nicode conversion failed (ICU error code = ");
293     printint(errcode);
294     printcstring(") discarding any remaining text");
295     enddiagnostic(1);
296 }
297 
298 #ifdef WORDS_BIGENDIAN
299 #define NATIVE_UTF32    kForm_UTF32BE
300 #else
301 #define NATIVE_UTF32    kForm_UTF32LE
302 #endif
303 
304 static void
apply_normalization(uint32_t * buf,int len,int norm)305 apply_normalization(uint32_t* buf, int len, int norm)
306 {
307     static TECkit_Converter normalizers[2] = { NULL, NULL };
308 
309     TECkit_Status status;
310     UInt32 inUsed, outUsed;
311     TECkit_Converter *normPtr = &normalizers[norm - 1];
312     if (*normPtr == NULL) {
313         status = TECkit_CreateConverter(NULL, 0, 1,
314             NATIVE_UTF32, NATIVE_UTF32 | (norm == 1 ? kForm_NFC : kForm_NFD),
315             &*normPtr);
316         if (status != kStatus_NoError) {
317             fprintf(stderr, "! Failed to create normalizer: error code = %d\n", (int)status);
318             uexit (1);
319         }
320     }
321 
322     status = TECkit_ConvertBuffer(*normPtr, (Byte*)buf, len * sizeof(UInt32), &inUsed,
323                 (Byte*)&buffer[first], sizeof(*buffer) * (bufsize - first), &outUsed, 1);
324     if (status != kStatus_NoError)
325         buffer_overflow();
326     last = first + outUsed / sizeof(*buffer);
327 }
328 
329 #ifdef WORDS_BIGENDIAN
330 #define UCNV_UTF32_NativeEndian UCNV_UTF32_BigEndian
331 #else
332 #define UCNV_UTF32_NativeEndian UCNV_UTF32_LittleEndian
333 #endif
334 
335 int
input_line(UFILE * f)336 input_line(UFILE* f)
337 {
338 static char* byteBuffer = NULL;
339 static uint32_t *utf32Buf = NULL;
340     int i, tmpLen;
341     int norm = getinputnormalizationstate();
342 #ifdef WIN32
343     const int fd = fileno(f->f);
344     if (fd == _fileno(stdin) && _isatty(fd)) {
345         f->encodingMode = WIN32CONSOLE;
346     }
347 #endif
348 
349     last = first;
350 
351     if (f->encodingMode == ICUMAPPING) {
352         uint32_t bytesRead = 0;
353         UConverter* cnv;
354         int outLen;
355         UErrorCode errorCode = U_ZERO_ERROR;
356 
357         if (byteBuffer == NULL)
358             byteBuffer = (char*) xmalloc(bufsize + 1);
359 
360         /* Recognize either LF or CR as a line terminator; skip initial LF if prev line ended with CR.  */
361         i = GETC(f->f);
362         if (f->skipNextLF) {
363             f->skipNextLF = 0;
364             if (i == '\n')
365                 i = GETC(f->f);
366         }
367 
368         if (i != EOF && i != '\n' && i != '\r')
369             byteBuffer[bytesRead++] = i;
370         if (i != EOF && i != '\n' && i != '\r')
371             while (bytesRead < bufsize && (i = GETC(f->f)) != EOF && i != '\n' && i != '\r')
372                 byteBuffer[bytesRead++] = i;
373 
374         if (i == EOF && errno != EINTR && bytesRead == 0)
375             return false;
376 
377         if (i != EOF && i != '\n' && i != '\r')
378             buffer_overflow();
379 
380         /* now apply the mapping to turn external bytes into Unicode characters in buffer */
381         cnv = (UConverter*)(f->conversionData);
382         switch (norm) {
383             case 1: // NFC
384             case 2: // NFD
385                 if (utf32Buf == NULL)
386                     utf32Buf = (uint32_t*) xcalloc(bufsize, sizeof(uint32_t));
387                 tmpLen = ucnv_toAlgorithmic(UCNV_UTF32_NativeEndian, cnv,
388                                             (char*)utf32Buf, bufsize * sizeof(*utf32Buf),
389                                             byteBuffer, bytesRead, &errorCode);
390                 if (errorCode != 0) {
391                     conversion_error((int)errorCode);
392                     return false;
393                 }
394                 apply_normalization(utf32Buf, tmpLen / sizeof(*utf32Buf), norm); // sets 'last' correctly
395                 break;
396 
397             default: // none
398                 outLen = ucnv_toAlgorithmic(UCNV_UTF32_NativeEndian, cnv,
399                                             (char*)&buffer[first], sizeof(*buffer) * (bufsize - first),
400                                             byteBuffer, bytesRead, &errorCode);
401                 if (errorCode != 0) {
402                     conversion_error((int)errorCode);
403                     return false;
404                 }
405                 outLen /= sizeof(*buffer);
406                 last = first + outLen;
407                 break;
408         }
409     } else {
410         /* Recognize either LF or CR as a line terminator; skip initial LF if prev line ended with CR.  */
411         i = get_uni_c(f);
412         if (f->skipNextLF) {
413             f->skipNextLF = 0;
414             if (i == '\n')
415                 i = get_uni_c(f);
416         }
417 
418         switch (norm) {
419             case 1: // NFC
420             case 2: // NFD
421                 // read Unicode chars into utf32Buf as UTF32
422                 if (utf32Buf == NULL)
423                     utf32Buf = (uint32_t*) xcalloc(bufsize, sizeof(uint32_t));
424                 tmpLen = 0;
425                 if (i != EOF && i != '\n' && i != '\r')
426                     utf32Buf[tmpLen++] = i;
427                 if (i != EOF && i != '\n' && i != '\r')
428                     while (tmpLen < bufsize && (i = get_uni_c(f)) != EOF && i != '\n' && i != '\r')
429                         utf32Buf[tmpLen++] = i;
430 
431                 if (i == EOF && errno != EINTR && tmpLen == 0)
432                     return false;
433 
434                 /* We didn't get the whole line because our buffer was too small.  */
435                 if (i != EOF && i != '\n' && i != '\r')
436                     buffer_overflow();
437                 apply_normalization(utf32Buf, tmpLen, norm);
438                 break;
439 
440             default: // none
441 #ifdef WIN32
442                 if (f->encodingMode == WIN32CONSOLE && i == 0x1a) /* Ctrl+Z */
443                     return false;
444 #endif
445                 if (last < bufsize && i != EOF && i != '\n' && i != '\r')
446                     buffer[last++] = i;
447                 if (i != EOF && i != '\n' && i != '\r')
448                     while (last < bufsize && (i = get_uni_c(f)) != EOF && i != '\n' && i != '\r')
449                         buffer[last++] = i;
450 
451                 if (i == EOF && errno != EINTR && last == first)
452                     return false;
453 
454                 /* We didn't get the whole line because our buffer was too small.  */
455                 if (i != EOF && i != '\n' && i != '\r')
456                     buffer_overflow();
457                 break;
458         }
459     }
460 
461     /* If line ended with CR, remember to skip following LF. */
462     if (i == '\r')
463         f->skipNextLF = 1;
464 
465     buffer[last] = ' ';
466     if (last >= maxbufstack)
467         maxbufstack = last;
468 
469     /* Trim trailing whitespace.  */
470     while (last > first && ISBLANK(buffer[last - 1]))
471         --last;
472 
473     return true;
474 }
475 
die(const_string s,int i)476 static void die(const_string s, int i)
477 {
478     fprintf(stderr, s, i);
479     fprintf(stderr, " - exiting\n");
480     exit(3);
481 }
482 
483 static UBreakIterator* brkIter = NULL;
484 static int brkLocaleStrNum = 0;
485 
486 void
linebreakstart(int f,integer localeStrNum,const uint16_t * text,integer textLength)487 linebreakstart(int f, integer localeStrNum, const uint16_t* text, integer textLength)
488 {
489     UErrorCode status = U_ZERO_ERROR;
490     char* locale = (char*)gettexstring(localeStrNum);
491 
492     if (fontarea[f] == OTGR_FONT_FLAG && strcmp(locale, "G") == 0) {
493         XeTeXLayoutEngine engine = (XeTeXLayoutEngine) fontlayoutengine[f];
494         if (initGraphiteBreaking(engine, text, textLength))
495             /* user asked for Graphite line breaking and the font supports it */
496             return;
497     }
498 
499     if ((localeStrNum != brkLocaleStrNum) && (brkIter != NULL)) {
500         ubrk_close(brkIter);
501         brkIter = NULL;
502     }
503 
504     if (brkIter == NULL) {
505         brkIter = ubrk_open(UBRK_LINE, locale, NULL, 0, &status);
506         if (U_FAILURE(status)) {
507             begindiagnostic();
508             printnl('E');
509             printcstring("rror ");
510             printint(status);
511             printcstring(" creating linebreak iterator for locale `");
512             printcstring(locale);
513             printcstring("'; trying default locale `en_us'.");
514             enddiagnostic(1);
515             if (brkIter != NULL)
516                 ubrk_close(brkIter);
517             status = U_ZERO_ERROR;
518             brkIter = ubrk_open(UBRK_LINE, "en_us", NULL, 0, &status);
519         }
520         free(locale);
521         brkLocaleStrNum = localeStrNum;
522     }
523 
524     if (brkIter == NULL) {
525         die("! failed to create linebreak iterator, status=%d", (int)status);
526     }
527 
528     ubrk_setText(brkIter, (UChar*) text, textLength, &status);
529 }
530 
531 int
linebreaknext()532 linebreaknext()
533 {
534     if (brkIter != NULL)
535         return ubrk_next((UBreakIterator*)brkIter);
536     else
537         return findNextGraphiteBreak();
538 }
539 
540 int
getencodingmodeandinfo(integer * info)541 getencodingmodeandinfo(integer* info)
542 {
543     /* \XeTeXinputencoding "enc-name"
544      *   -> name is packed in |nameoffile| as a C string, starting at [1]
545      * Check if it's a built-in name; if not, try to open an ICU converter by that name
546      */
547     UErrorCode err = U_ZERO_ERROR;
548     UConverter* cnv;
549     char* name = (char*)nameoffile + 1;
550     *info = 0;
551     if (strcasecmp(name, "auto") == 0) {
552         return AUTO;
553     }
554     if (strcasecmp(name, "utf8") == 0) {
555         return UTF8;
556     }
557     if (strcasecmp(name, "utf16") == 0) {   /* depends on host platform */
558 #ifdef WORDS_BIGENDIAN
559         return UTF16BE;
560 #else
561         return UTF16LE;
562 #endif
563     }
564     if (strcasecmp(name, "utf16be") == 0) {
565         return UTF16BE;
566     }
567     if (strcasecmp(name, "utf16le") == 0) {
568         return UTF16LE;
569     }
570     if (strcasecmp(name, "bytes") == 0) {
571         return RAW;
572     }
573 
574     /* try for an ICU converter */
575     cnv = ucnv_open(name, &err);
576     if (cnv == NULL) {
577         begindiagnostic();
578         printnl('U'); /* ensure message starts on a new line */
579         printcstring("nknown encoding `");
580         printcstring(name);
581         printcstring("'; reading as raw bytes");
582         enddiagnostic(1);
583         return RAW;
584     } else {
585         ucnv_close(cnv);
586         *info = maketexstring(name);
587         return ICUMAPPING;
588     }
589 }
590 
591 void
printutf8str(const unsigned char * str,int len)592 printutf8str(const unsigned char* str, int len)
593 {
594     while (len-- > 0)
595         printrawchar(*(str++), true); /* bypass utf-8 encoding done in print_char() */
596 }
597 
598 void
printchars(const unsigned short * str,int len)599 printchars(const unsigned short* str, int len)
600 {
601     while (len-- > 0)
602         printchar(*(str++));
603 }
604 
605 #ifdef WORDS_BIGENDIAN
606 #define UTF16_NATIVE kForm_UTF16BE
607 #else
608 #define UTF16_NATIVE kForm_UTF16LE
609 #endif
610 
611 static void*
load_mapping_file(const char * s,const char * e,char byteMapping)612 load_mapping_file(const char* s, const char* e, char byteMapping)
613 {
614     char* mapPath;
615     TECkit_Converter cnv = 0;
616     char* buffer = (char*) xmalloc(e - s + 5);
617     strncpy(buffer, s, e - s);
618     buffer[e - s] = 0;
619     strcat(buffer, ".tec");
620     mapPath = kpse_find_file(buffer, kpse_miscfonts_format, 1);
621 
622     if (mapPath) {
623         FILE* mapFile = fopen(mapPath, FOPEN_RBIN_MODE);
624         free(mapPath);
625         if (mapFile) {
626             uint32_t mappingSize;
627             Byte* mapping;
628             TECkit_Status status;
629             fseek(mapFile, 0, SEEK_END);
630             mappingSize = ftell(mapFile);
631             fseek(mapFile, 0, SEEK_SET);
632             mapping = (Byte*) xmalloc(mappingSize);
633             fread(mapping, 1, mappingSize, mapFile);
634             fclose(mapFile);
635             if (byteMapping != 0)
636                 status = TECkit_CreateConverter(mapping, mappingSize,
637                                             false,
638                                             UTF16_NATIVE, kForm_Bytes,
639                                             &cnv);
640             else
641                 status = TECkit_CreateConverter(mapping, mappingSize,
642                                             true,
643                                             UTF16_NATIVE, UTF16_NATIVE,
644                                             &cnv);
645             free(mapping);
646         }
647         if (cnv == NULL)
648             fontmappingwarning(buffer, strlen(buffer), 2); /* not loadable */
649         else if (gettracingfontsstate() > 1)
650             fontmappingwarning(buffer, strlen(buffer), 0); /* tracing */
651     } else {
652         fontmappingwarning(buffer, strlen(buffer), 1); /* not found */
653     }
654 
655     free(buffer);
656 
657     return cnv;
658 }
659 
660 char *saved_mapping_name = NULL;
661 void
checkfortfmfontmapping()662 checkfortfmfontmapping()
663 {
664     char* cp = strstr((char*)nameoffile + 1, ":mapping=");
665     if (saved_mapping_name != NULL) {
666         free(saved_mapping_name);
667         saved_mapping_name = NULL;
668     }
669     if (cp != NULL) {
670         *cp = 0;
671         cp += 9;
672         while (*cp && *cp <= ' ')
673             ++cp;
674         if (*cp)
675             saved_mapping_name = xstrdup(cp);
676     }
677 }
678 
679 void*
loadtfmfontmapping()680 loadtfmfontmapping()
681 {
682     void* rval = NULL;
683     if (saved_mapping_name != NULL) {
684         rval = load_mapping_file(saved_mapping_name,
685                 saved_mapping_name + strlen(saved_mapping_name), 1);
686         free(saved_mapping_name);
687         saved_mapping_name = NULL;
688     }
689     return rval;
690 }
691 
692 int
applytfmfontmapping(void * cnv,int c)693 applytfmfontmapping(void* cnv, int c)
694 {
695     UniChar in = c;
696     Byte out[2];
697     UInt32 inUsed, outUsed;
698     TECkit_Status status = TECkit_ConvertBuffer((TECkit_Converter)cnv,
699             (const Byte*)&in, sizeof(in), &inUsed, out, sizeof(out), &outUsed, 1);
700     if (outUsed < 1)
701         return 0;
702     else
703         return out[0];
704 }
705 
706 double
read_double(const char ** s)707 read_double(const char** s)
708 {
709     int neg = 0;
710     double val = 0.0;
711     const char* cp = *s;
712 
713     while (*cp == ' '|| *cp == '\t')
714         ++cp;
715     if (*cp == '-') {
716         neg = 1;
717         ++cp;
718     } else if (*cp == '+') {
719         ++cp;
720     }
721 
722     while (*cp >= '0' && *cp <= '9') {
723         val = val * 10.0 + *cp - '0';
724         ++cp;
725     }
726     if (*cp == '.') {
727         double dec = 10.0;
728         ++cp;
729         while (*cp >= '0' && *cp <= '9') {
730             val = val + (*cp - '0') / dec;
731             ++cp;
732             dec = dec * 10.0;
733         }
734     }
735     *s = cp;
736 
737     return neg ? -val : val;
738 }
739 
740 static hb_tag_t
read_tag_with_param(const char * cp,int * param)741 read_tag_with_param(const char* cp, int* param)
742 {
743     const char* cp2;
744     hb_tag_t tag;
745 
746     cp2 = cp;
747     while (*cp2 && (*cp2 != ':') && (*cp2 != ';') && (*cp2 != ',') && (*cp2 != '='))
748         ++cp2;
749 
750     tag = hb_tag_from_string(cp, cp2 - cp);
751 
752     cp = cp2;
753     if (*cp == '=') {
754         int neg = 0;
755         ++cp;
756         if (*cp == '-') {
757             ++neg;
758             ++cp;
759         }
760         while (*cp >= '0' && *cp <= '9') {
761             *param = *param * 10 + *cp - '0';
762             ++cp;
763         }
764         if (neg)
765             *param = -(*param);
766     }
767 
768     return tag;
769 }
770 
771 unsigned int
read_rgb_a(const char ** cp)772 read_rgb_a(const char** cp)
773 {
774     uint32_t rgbValue = 0;
775     uint32_t alpha = 0;
776     int i;
777     for (i = 0; i < 6; ++i) {
778         if ((**cp >= '0') && (**cp <= '9'))
779             rgbValue = (rgbValue << 4) + **cp - '0';
780         else if ((**cp >= 'A') && (**cp <= 'F'))
781             rgbValue = (rgbValue << 4) + **cp - 'A' + 10;
782         else if ((**cp >= 'a') && (**cp <= 'f'))
783             rgbValue = (rgbValue << 4) + **cp - 'a' + 10;
784         else
785             return 0x000000FF;
786         (*cp)++;
787     }
788     rgbValue <<= 8;
789     for (i = 0; i < 2; ++i) {
790         if ((**cp >= '0') && (**cp <= '9'))
791             alpha = (alpha << 4) + **cp - '0';
792         else if ((**cp >= 'A') && (**cp <= 'F'))
793             alpha = (alpha << 4) + **cp - 'A' + 10;
794         else if ((**cp >= 'a') && (**cp <= 'f'))
795             alpha = (alpha << 4) + **cp - 'a' + 10;
796         else
797             break;
798         (*cp)++;
799     }
800     if (i == 2)
801         rgbValue += alpha;
802     else
803         rgbValue += 0xFF;
804     return rgbValue;
805 }
806 
807 int
readCommonFeatures(const char * feat,const char * end,float * extend,float * slant,float * embolden,float * letterspace,uint32_t * rgbValue)808 readCommonFeatures(const char* feat, const char* end, float* extend, float* slant, float* embolden, float* letterspace, uint32_t* rgbValue)
809     // returns 1 to go to next_option, -1 for bad_option, 0 to continue
810 {
811     const char* sep;
812     if (strncmp(feat, "mapping", 7) == 0) {
813         sep = feat + 7;
814         if (*sep != '=')
815             return -1;
816         loadedfontmapping = load_mapping_file(sep + 1, end, 0);
817         return 1;
818     }
819 
820     if (strncmp(feat, "extend", 6) == 0) {
821         sep = feat + 6;
822         if (*sep != '=')
823             return -1;
824         ++sep;
825         *extend = read_double(&sep);
826         return 1;
827     }
828 
829     if (strncmp(feat, "slant", 5) == 0) {
830         sep = feat + 5;
831         if (*sep != '=')
832             return -1;
833         ++sep;
834         *slant = read_double(&sep);
835         return 1;
836     }
837 
838     if (strncmp(feat, "embolden", 8) == 0) {
839         sep = feat + 8;
840         if (*sep != '=')
841             return -1;
842         ++sep;
843         *embolden = read_double(&sep);
844         return 1;
845     }
846 
847     if (strncmp(feat, "letterspace", 11) == 0) {
848         sep = feat + 11;
849         if (*sep != '=')
850             return -1;
851         ++sep;
852         *letterspace = read_double(&sep);
853         return 1;
854     }
855 
856     if (strncmp(feat, "color", 5) == 0) {
857         const char* s;
858         sep = feat + 5;
859         if (*sep != '=')
860             return -1;
861         ++sep;
862         s = sep;
863         *rgbValue = read_rgb_a(&sep);
864         if ((sep == s+6) || (sep == s+8))
865             loadedfontflags |= FONT_FLAGS_COLORED;
866         else
867             return -1;
868         return 1;
869     }
870 
871     return 0;
872 }
873 
874 static bool
readFeatureNumber(const char * s,const char * e,hb_tag_t * f,int * v)875 readFeatureNumber(const char* s, const char* e, hb_tag_t* f, int* v)
876     /* s...e is a "id=setting" string; */
877 {
878     *f = 0;
879     *v = 0;
880     if (*s < '0' || *s > '9')
881         return false;
882     while (*s >= '0' && *s <= '9')
883         *f = *f * 10 + *s++ - '0';
884     while ((*s == ' ') || (*s == '\t'))
885         ++s;
886     if (*s++ != '=')
887         /* no setting was specified */
888         return false;
889 
890     if (*s < '0' || *s > '9')
891         return false;
892     while (*s >= '0' && *s <= '9')
893         *v = *v * 10 + *s++ - '0';
894     while ((*s == ' ') || (*s == '\t'))
895         ++s;
896     if (s != e)
897         return false;
898     return true;
899 }
900 
901 static void*
loadOTfont(PlatformFontRef fontRef,XeTeXFont font,Fixed scaled_size,const char * cp1)902 loadOTfont(PlatformFontRef fontRef, XeTeXFont font, Fixed scaled_size, const char* cp1)
903 {
904     XeTeXLayoutEngine engine;
905     hb_tag_t script = HB_TAG_NONE;
906     char * language = NULL;
907     hb_feature_t* features = NULL;
908     char** shapers = NULL; /* NULL-terminated array */
909     int nFeatures = 0;
910     int nShapers = 0;
911 
912     const char* cp2;
913     const char* cp3;
914 
915     hb_tag_t tag;
916 
917     uint32_t rgbValue = 0x000000FF;
918 
919     float extend = 1.0;
920     float slant = 0.0;
921     float embolden = 0.0;
922     float letterspace = 0.0;
923 
924     int i;
925 
926     char reqEngine = getReqEngine();
927 
928     if (reqEngine == 'O' || reqEngine == 'G') {
929         shapers = (char**) xrealloc(shapers, (nShapers + 1) * sizeof(char *));
930         if (reqEngine == 'O')
931             shapers[nShapers] = "ot";
932         else if (reqEngine == 'G')
933             shapers[nShapers] = "graphite2";
934         nShapers++;
935     }
936 
937     if (reqEngine == 'G') {
938         char* tmpShapers[] = {shapers[0]};
939         /* create a default engine so we can query the font for Graphite features;
940          * because of font caching, it's cheap to discard this and create the real one later */
941         engine = createLayoutEngine(fontRef, font, script, language,
942                 features, nFeatures, tmpShapers, rgbValue, extend, slant, embolden);
943 
944         if (engine == NULL)
945             return NULL;
946     }
947 
948     /* scan the feature string (if any) */
949     if (cp1 != NULL) {
950         while (*cp1) {
951             if ((*cp1 == ':') || (*cp1 == ';') || (*cp1 == ','))
952                 ++cp1;
953             while ((*cp1 == ' ') || (*cp1 == '\t')) /* skip leading whitespace */
954                 ++cp1;
955             if (*cp1 == 0)  /* break if end of string */
956                 break;
957 
958             cp2 = cp1;
959             while (*cp2 && (*cp2 != ':') && (*cp2 != ';') && (*cp2 != ','))
960                 ++cp2;
961 
962             if (strncmp(cp1, "script", 6) == 0) {
963                 cp3 = cp1 + 6;
964                 if (*cp3 != '=')
965                     goto bad_option;
966                 ++cp3;
967                 script = hb_tag_from_string(cp3, cp2 - cp3);
968                 goto next_option;
969             }
970 
971             if (strncmp(cp1, "language", 8) == 0) {
972                 cp3 = cp1 + 8;
973                 if (*cp3 != '=')
974                     goto bad_option;
975                 ++cp3;
976                 language = (char*)xmalloc(cp2 - cp3 + 1);
977                 language[cp2 - cp3] = '\0';
978                 memcpy(language, cp3, cp2 - cp3);
979                 goto next_option;
980             }
981 
982             if (strncmp(cp1, "shaper", 6) == 0) {
983                 cp3 = cp1 + 6;
984                 if (*cp3 != '=')
985                     goto bad_option;
986                 ++cp3;
987                 shapers = (char**) xrealloc(shapers, (nShapers + 1) * sizeof(char *));
988                 /* some dumb systems have no strndup() */
989                 shapers[nShapers] = strdup(cp3);
990                 shapers[nShapers][cp2 - cp3] = '\0';
991                 nShapers++;
992                 goto next_option;
993             }
994 
995             i = readCommonFeatures(cp1, cp2, &extend, &slant, &embolden, &letterspace, &rgbValue);
996             if (i == 1)
997                 goto next_option;
998             else if (i == -1)
999                 goto bad_option;
1000 
1001             if (reqEngine == 'G') {
1002                 int value = 0;
1003                 if (readFeatureNumber(cp1, cp2, &tag, &value)
1004                  || findGraphiteFeature(engine, cp1, cp2, &tag, &value)) {
1005                     features = (hb_feature_t*) xrealloc(features, (nFeatures + 1) * sizeof(hb_feature_t));
1006                     features[nFeatures].tag = tag;
1007                     features[nFeatures].value = value;
1008                     features[nFeatures].start = 0;
1009                     features[nFeatures].end = (unsigned int) -1;
1010                     nFeatures++;
1011                     goto next_option;
1012                 }
1013             }
1014 
1015             if (*cp1 == '+') {
1016                 int param = 0;
1017                 tag = read_tag_with_param(cp1 + 1, &param);
1018                 features = (hb_feature_t*) xrealloc(features, (nFeatures + 1) * sizeof(hb_feature_t));
1019                 features[nFeatures].tag = tag;
1020                 features[nFeatures].start = 0;
1021                 features[nFeatures].end = (unsigned int) -1;
1022                 // for backward compatibility with pre-0.9999 where feature
1023                 // indices started from 0
1024                 if (param >= 0)
1025                     param++;
1026                 features[nFeatures].value = param;
1027                 nFeatures++;
1028                 goto next_option;
1029             }
1030 
1031             if (*cp1 == '-') {
1032                 ++cp1;
1033                 tag = hb_tag_from_string(cp1, cp2 - cp1);
1034                 features = (hb_feature_t*) xrealloc(features, (nFeatures + 1) * sizeof(hb_feature_t));
1035                 features[nFeatures].tag = tag;
1036                 features[nFeatures].start = 0;
1037                 features[nFeatures].end = (unsigned int) -1;
1038                 features[nFeatures].value = 0;
1039                 nFeatures++;
1040                 goto next_option;
1041             }
1042 
1043             if (strncmp(cp1, "vertical", 8) == 0) {
1044                 cp3 = cp2;
1045                 if (*cp3 == ';' || *cp3 == ':' || *cp3 == ',')
1046                     --cp3;
1047                 while (*cp3 == '\0' || *cp3 == ' ' || *cp3 == '\t')
1048                     --cp3;
1049                 if (*cp3)
1050                     ++cp3;
1051                 if (cp3 == cp1 + 8) {
1052                     loadedfontflags |= FONT_FLAGS_VERTICAL;
1053                     goto next_option;
1054                 }
1055             }
1056 
1057         bad_option:
1058             fontfeaturewarning((void*) cp1, cp2 - cp1, 0, 0);
1059 
1060         next_option:
1061             cp1 = cp2;
1062         }
1063     }
1064 
1065     if (shapers != NULL) {
1066         shapers = (char**) xrealloc(shapers, (nShapers + 1) * sizeof(char *));
1067         shapers[nShapers] = NULL;
1068     }
1069 
1070     if (embolden != 0.0)
1071         embolden = embolden * Fix2D(scaled_size) / 100.0;
1072 
1073     if (letterspace != 0.0)
1074         loadedfontletterspace = (letterspace / 100.0) * scaled_size;
1075 
1076     if ((loadedfontflags & FONT_FLAGS_COLORED) == 0)
1077         rgbValue = 0x000000FF;
1078 
1079     if ((loadedfontflags & FONT_FLAGS_VERTICAL) != 0)
1080         setFontLayoutDir(font, 1);
1081 
1082     engine = createLayoutEngine(fontRef, font, script, language,
1083                     features, nFeatures, shapers, rgbValue, extend, slant, embolden);
1084 
1085     if (engine == 0) {
1086         // only free these if creation failed, otherwise the engine now owns them
1087         free(features);
1088         free(shapers);
1089     } else {
1090         nativefonttypeflag = OTGR_FONT_FLAG;
1091     }
1092 
1093     return engine;
1094 }
1095 
1096 static void
splitFontName(char * name,char ** var,char ** feat,char ** end,int * index)1097 splitFontName(char* name, char** var, char** feat, char** end, int* index)
1098 {
1099     *var = NULL;
1100     *feat = NULL;
1101     *index = 0;
1102     if (*name == '[') {
1103         int withinFileName = 1;
1104 #ifdef WIN32
1105         char* start = name + 1;
1106 #endif
1107         ++name;
1108         while (*name) {
1109             if (withinFileName && *name == ']') {
1110                 withinFileName = 0;
1111                 if (*var == NULL)
1112                     *var = name;
1113             } else if (*name == ':') {
1114                 if (withinFileName && *var == NULL
1115 #ifdef WIN32
1116                     && !((name - start == 1) && isalpha(*start))
1117 #endif
1118                     ) {
1119                     *var = name;
1120                     ++name;
1121                     while (*name >= '0' && *name <= '9')
1122                         *index = *index * 10 + *name++ - '0';
1123                     --name;
1124                 } else if (!withinFileName && *feat == NULL)
1125                     *feat = name;
1126             }
1127             ++name;
1128         }
1129         *end = name;
1130     } else {
1131         while (*name) {
1132             if (*name == '/' && *var == NULL && *feat == NULL)
1133                 *var = name;
1134             else if (*name == ':' && *feat == NULL)
1135                 *feat = name;
1136             ++name;
1137         }
1138         *end = name;
1139     }
1140     if (*feat == NULL)
1141         *feat = name;
1142     if (*var == NULL)
1143         *var = *feat;
1144 }
1145 
1146 void*
findnativefont(unsigned char * uname,integer scaled_size)1147 findnativefont(unsigned char* uname, integer scaled_size)
1148     /* scaled_size here is in TeX points, or is a negative integer for 'scaled' */
1149 {
1150     void* rval = NULL;
1151     char* nameString;
1152     char* var;
1153     char* feat;
1154     char* end;
1155     char* name = (char*)uname;
1156     char* varString = NULL;
1157     char* featString = NULL;
1158     PlatformFontRef fontRef;
1159     XeTeXFont font = NULL;
1160     int index = 0;
1161 
1162     loadedfontmapping = NULL;
1163     loadedfontflags = 0;
1164     loadedfontletterspace = 0;
1165 
1166     splitFontName(name, &var, &feat, &end, &index);
1167     nameString = (char*) xmalloc(var - name + 1);
1168     strncpy(nameString, name, var - name);
1169     nameString[var - name] = 0;
1170 
1171     if (feat > var) {
1172         varString = (char*) xmalloc(feat - var);
1173         strncpy(varString, var + 1, feat - var - 1);
1174         varString[feat - var - 1] = 0;
1175     }
1176 
1177     if (end > feat) {
1178         featString = (char*) xmalloc(end - feat);
1179         strncpy(featString, feat + 1, end - feat - 1);
1180         featString[end - feat - 1] = 0;
1181     }
1182 
1183     // check for "[filename]" form, don't search maps in this case
1184     if (nameString[0] == '[') {
1185         char* path = kpse_find_file(nameString + 1, kpse_opentype_format, 0);
1186         if (path == NULL)
1187             path = kpse_find_file(nameString + 1, kpse_truetype_format, 0);
1188         if (path == NULL)
1189             path = kpse_find_file(nameString + 1, kpse_type1_format, 0);
1190         if (path != NULL) {
1191             if (scaled_size < 0) {
1192                 font = createFontFromFile(path, index, 655360L);
1193                 if (font != NULL) {
1194                     Fixed dsize = D2Fix(getDesignSize(font));
1195                     if (scaled_size == -1000)
1196                         scaled_size = dsize;
1197                     else
1198                         scaled_size = zxnoverd(dsize, -scaled_size, 1000);
1199                     deleteFont(font);
1200                 }
1201             }
1202             font = createFontFromFile(path, index, scaled_size);
1203             if (font != NULL) {
1204                 loadedfontdesignsize = D2Fix(getDesignSize(font));
1205 
1206                 /* This is duplicated in XeTeXFontMgr::findFont! */
1207                 setReqEngine(0);
1208                 if (varString) {
1209                     if (strncmp(varString, "/AAT", 4) == 0)
1210                         setReqEngine('A');
1211                     else if ((strncmp(varString, "/OT", 3) == 0) || (strncmp(varString, "/ICU", 4) == 0))
1212                         setReqEngine('O');
1213                     else if (strncmp(varString, "/GR", 3) == 0)
1214                         setReqEngine('G');
1215                 }
1216 
1217                 rval = loadOTfont(0, font, scaled_size, featString);
1218                 if (rval == NULL)
1219                     deleteFont(font);
1220                 if (rval != NULL && gettracingfontsstate() > 0) {
1221                     begindiagnostic();
1222                     zprintnl(' ');
1223                     printcstring("-> ");
1224                     printcstring(path);
1225                     zenddiagnostic(0);
1226                 }
1227             }
1228         }
1229     } else {
1230         fontRef = findFontByName(nameString, varString, Fix2D(scaled_size));
1231 
1232         if (fontRef != 0) {
1233             /* update nameoffile to the full name of the font, for error messages during font loading */
1234             const char* fullName = getFullName(fontRef);
1235             namelength = strlen(fullName);
1236             if (featString != NULL)
1237                 namelength += strlen(featString) + 1;
1238             if (varString != NULL)
1239                 namelength += strlen(varString) + 1;
1240             free(nameoffile);
1241             nameoffile = xmalloc(namelength + 4); /* +2 would be correct: initial space, final NUL */
1242             nameoffile[0] = ' ';
1243             strcpy((char*)nameoffile + 1, fullName);
1244 
1245             if (scaled_size < 0) {
1246                 font = createFont(fontRef, scaled_size);
1247                 if (font != NULL) {
1248                     Fixed dsize = D2Fix(getDesignSize(font));
1249                     if (scaled_size == -1000)
1250                         scaled_size = dsize;
1251                     else
1252                         scaled_size = zxnoverd(dsize, -scaled_size, 1000);
1253                     deleteFont(font);
1254                 }
1255             }
1256 
1257             font = createFont(fontRef, scaled_size);
1258             if (font != NULL) {
1259 #ifdef XETEX_MAC
1260                 /* decide whether to use AAT or OpenType rendering with this font */
1261                 if (getReqEngine() == 'A') {
1262                     rval = loadAATfont(fontRef, scaled_size, featString);
1263                     if (rval == NULL)
1264                         deleteFont(font);
1265                 } else {
1266                     if (getReqEngine() == 'O' || getReqEngine() == 'G' ||
1267                             getFontTablePtr(font, kGSUB) != NULL || getFontTablePtr(font, kGPOS) != NULL)
1268                         rval = loadOTfont(fontRef, font, scaled_size, featString);
1269 
1270                     /* loadOTfont failed or the above check was false */
1271                     if (rval == NULL)
1272                         rval = loadAATfont(fontRef, scaled_size, featString);
1273 
1274                     if (rval == NULL)
1275                         deleteFont(font);
1276                 }
1277 #else
1278                 rval = loadOTfont(fontRef, font, scaled_size, featString);
1279                 if (rval == NULL)
1280                     deleteFont(font);
1281 #endif
1282             }
1283 
1284             /* append the style and feature strings, so that \show\fontID will give a full result */
1285             if (varString != NULL && *varString != 0) {
1286                 strcat((char*)nameoffile + 1, "/");
1287                 strcat((char*)nameoffile + 1, varString);
1288             }
1289             if (featString != NULL && *featString != 0) {
1290                 strcat((char*)nameoffile + 1, ":");
1291                 strcat((char*)nameoffile + 1, featString);
1292             }
1293             namelength = strlen((char*)nameoffile + 1);
1294         }
1295     }
1296 
1297     if (varString != NULL)
1298         free(varString);
1299 
1300     if (featString != NULL)
1301         free(featString);
1302 
1303     free(nameString);
1304 
1305     return rval;
1306 }
1307 
1308 void
releasefontengine(void * engine,int type_flag)1309 releasefontengine(void* engine, int type_flag)
1310 {
1311 #ifdef XETEX_MAC
1312     if (type_flag == AAT_FONT_FLAG) {
1313         CFRelease((CFDictionaryRef)engine);
1314     } else
1315 #endif
1316     if (type_flag == OTGR_FONT_FLAG) {
1317         deleteLayoutEngine((XeTeXLayoutEngine)engine);
1318     }
1319 }
1320 
1321 /* params are given as 'integer' in the header file, but are really TeX scaled integers */
1322 void
otgetfontmetrics(void * pEngine,scaled * ascent,scaled * descent,scaled * xheight,scaled * capheight,scaled * slant)1323 otgetfontmetrics(void* pEngine, scaled* ascent, scaled* descent, scaled* xheight, scaled* capheight, scaled* slant)
1324 {
1325     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1326     float a, d;
1327 
1328     getAscentAndDescent(engine, &a, &d);
1329     *ascent = D2Fix(a);
1330     *descent = D2Fix(d);
1331 
1332     *slant = D2Fix(Fix2D(getSlant(getFont(engine))) * getExtendFactor(engine)
1333                     + getSlantFactor(engine));
1334 
1335     /* get cap and x height from OS/2 table */
1336     getCapAndXHeight(engine, &a, &d);
1337     *capheight = D2Fix(a);
1338     *xheight = D2Fix(d);
1339 
1340     /* fallback in case the font does not have OS/2 table */
1341     if (*xheight == 0) {
1342         int glyphID = mapCharToGlyph(engine, 'x');
1343         if (glyphID != 0) {
1344             getGlyphHeightDepth(engine, glyphID, &a, &d);
1345             *xheight = D2Fix(a);
1346         } else {
1347             *xheight = *ascent / 2; /* arbitrary figure if there's no 'x' in the font */
1348         }
1349     }
1350 
1351     if (*capheight == 0) {
1352         int glyphID = mapCharToGlyph(engine, 'X');
1353         if (glyphID != 0) {
1354             getGlyphHeightDepth(engine, glyphID, &a, &d);
1355             *capheight = D2Fix(a);
1356         } else {
1357             *capheight = *ascent; /* arbitrary figure if there's no 'X' in the font */
1358         }
1359     }
1360 }
1361 
1362 integer
otfontget(integer what,void * pEngine)1363 otfontget(integer what, void* pEngine)
1364 {
1365     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1366     XeTeXFont fontInst = getFont(engine);
1367     switch (what) {
1368         case XeTeX_count_glyphs:
1369             return countGlyphs(fontInst);
1370             break;
1371 
1372         case XeTeX_count_features: /* ie Graphite features */
1373             return countGraphiteFeatures(engine);
1374             break;
1375 
1376         case XeTeX_OT_count_scripts:
1377             return countScripts(fontInst);
1378             break;
1379     }
1380     return 0;
1381 }
1382 
1383 
1384 integer
otfontget1(integer what,void * pEngine,integer param)1385 otfontget1(integer what, void* pEngine, integer param)
1386 {
1387     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1388     XeTeXFont fontInst = getFont(engine);
1389     switch (what) {
1390         case XeTeX_OT_count_languages:
1391             return countLanguages(fontInst, param);
1392             break;
1393 
1394         case XeTeX_OT_script_code:
1395             return getIndScript(fontInst, param);
1396             break;
1397 
1398         /* for graphite fonts...*/
1399         case XeTeX_feature_code:
1400             return getGraphiteFeatureCode(engine, param);
1401             break;
1402         case XeTeX_is_exclusive_feature:
1403             return 1;
1404             break;
1405         case XeTeX_count_selectors:
1406             return countGraphiteFeatureSettings(engine, param);
1407             break;
1408     }
1409     return 0;
1410 }
1411 
1412 
1413 integer
otfontget2(integer what,void * pEngine,integer param1,integer param2)1414 otfontget2(integer what, void* pEngine, integer param1, integer param2)
1415 {
1416     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1417     XeTeXFont fontInst = getFont(engine);
1418     switch (what) {
1419         case XeTeX_OT_language_code:
1420             return getIndLanguage(fontInst, param1, param2);
1421             break;
1422 
1423         case XeTeX_OT_count_features:
1424             return countFeatures(fontInst, param1, param2);
1425             break;
1426 
1427         /* for graphite fonts */
1428         case XeTeX_selector_code:
1429             return getGraphiteFeatureSettingCode(engine, param1, param2);
1430             break;
1431         case XeTeX_is_default_selector:
1432             return getGraphiteFeatureDefaultSetting(engine, param1) == param2;
1433             break;
1434     }
1435 
1436     return 0;
1437 }
1438 
1439 
1440 integer
otfontget3(integer what,void * pEngine,integer param1,integer param2,integer param3)1441 otfontget3(integer what, void* pEngine, integer param1, integer param2, integer param3)
1442 {
1443     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1444     XeTeXFont fontInst = getFont(engine);
1445     switch (what) {
1446         case XeTeX_OT_feature_code:
1447             return getIndFeature(fontInst, param1, param2, param3);
1448             break;
1449     }
1450 
1451     return 0;
1452 }
1453 
1454 void
grprintfontname(integer what,void * pEngine,integer param1,integer param2)1455 grprintfontname(integer what, void* pEngine, integer param1, integer param2)
1456 {
1457     char* name = NULL;
1458     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1459     switch (what) {
1460         case XeTeX_feature_name:
1461             name = getGraphiteFeatureLabel(engine, param1);
1462             break;
1463         case XeTeX_selector_name:
1464             name = getGraphiteFeatureSettingLabel(engine, param1, param2);
1465             break;
1466     }
1467 
1468     if (name != NULL) {
1469         printcstring(name);
1470         gr_label_destroy(name);
1471     }
1472 }
1473 
1474 integer
grfontgetnamed(integer what,void * pEngine)1475 grfontgetnamed(integer what, void* pEngine)
1476 {
1477     long rval = -1;
1478     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1479     switch (what) {
1480         case XeTeX_find_feature_by_name:
1481             rval = findGraphiteFeatureNamed(engine, (const char*)nameoffile + 1, namelength);
1482             break;
1483     }
1484     return rval;
1485 }
1486 
1487 integer
grfontgetnamed1(integer what,void * pEngine,integer param)1488 grfontgetnamed1(integer what, void* pEngine, integer param)
1489 {
1490     long rval = -1;
1491     XeTeXLayoutEngine engine = (XeTeXLayoutEngine)pEngine;
1492     switch (what) {
1493         case XeTeX_find_selector_by_name:
1494             rval = findGraphiteFeatureSettingNamed(engine, param, (const char*)nameoffile + 1, namelength);
1495             break;
1496     }
1497     return rval;
1498 }
1499 
1500 #define XDV_FLAG_VERTICAL       0x0100
1501 #define XDV_FLAG_COLORED        0x0200
1502 #define XDV_FLAG_EXTEND         0x1000
1503 #define XDV_FLAG_SLANT          0x2000
1504 #define XDV_FLAG_EMBOLDEN       0x4000
1505 
1506 #ifdef XETEX_MAC
1507 static UInt32
cgColorToRGBA32(CGColorRef color)1508 cgColorToRGBA32(CGColorRef color)
1509 {
1510     const CGFloat *components = CGColorGetComponents(color);
1511 
1512     UInt32 rval = (UInt8)(components[0] * 255.0 + 0.5);
1513     rval <<= 8;
1514     rval += (UInt8)(components[1] * 255.0 + 0.5);
1515     rval <<= 8;
1516     rval += (UInt8)(components[2] * 255.0 + 0.5);
1517     rval <<= 8;
1518     rval += (UInt8)(components[3] * 255.0 + 0.5);
1519     return rval;
1520 }
1521 #endif
1522 
1523 static int xdvBufSize = 0;
1524 
1525 int
makeXDVGlyphArrayData(void * pNode)1526 makeXDVGlyphArrayData(void* pNode)
1527 {
1528     unsigned char* cp;
1529     uint16_t* glyphIDs;
1530     memoryword* p = (memoryword*) pNode;
1531     void* glyph_info;
1532     FixedPoint* locations;
1533     Fixed width;
1534     uint16_t glyphCount = native_glyph_count(p);
1535 
1536     int i = glyphCount * native_glyph_info_size + 8; /* to guarantee enough space in the buffer */
1537     if (i > xdvBufSize) {
1538         if (xdvbuffer != NULL)
1539             free(xdvbuffer);
1540         xdvBufSize = ((i / 1024) + 1) * 1024;
1541         xdvbuffer = (char*) xmalloc(xdvBufSize);
1542     }
1543 
1544     glyph_info = native_glyph_info_ptr(p);
1545     locations = (FixedPoint*)glyph_info;
1546     glyphIDs = (uint16_t*)(locations + glyphCount);
1547 
1548     cp = (unsigned char*)xdvbuffer;
1549 
1550     width = node_width(p);
1551     *cp++ = (width >> 24) & 0xff;
1552     *cp++ = (width >> 16) & 0xff;
1553     *cp++ = (width >> 8) & 0xff;
1554     *cp++ = width & 0xff;
1555 
1556     *cp++ = (glyphCount >> 8) & 0xff;
1557     *cp++ = glyphCount & 0xff;
1558 
1559     for (i = 0; i < glyphCount; ++i) {
1560         Fixed x = locations[i].x;
1561         Fixed y = locations[i].y;
1562         *cp++ = (x >> 24) & 0xff;
1563         *cp++ = (x >> 16) & 0xff;
1564         *cp++ = (x >> 8) & 0xff;
1565         *cp++ = x & 0xff;
1566         *cp++ = (y >> 24) & 0xff;
1567         *cp++ = (y >> 16) & 0xff;
1568         *cp++ = (y >> 8) & 0xff;
1569         *cp++ = y & 0xff;
1570     }
1571 
1572     for (i = 0; i < glyphCount; ++i) {
1573         uint16_t g = glyphIDs[i];
1574         *cp++ = (g >> 8) & 0xff;
1575         *cp++ = g & 0xff;
1576     }
1577 
1578     return ((char*)cp - xdvbuffer);
1579 }
1580 
1581 int
makefontdef(integer f)1582 makefontdef(integer f)
1583 {
1584     uint16_t flags = 0;
1585     uint32_t rgba;
1586     Fixed size;
1587     const char* filename;
1588     uint32_t index;
1589     uint8_t filenameLen;
1590     int fontDefLength;
1591     char* cp;
1592     PlatformFontRef fontRef = 0;
1593     float extend = 1.0;
1594     float slant = 0.0;
1595     float embolden = 0.0;
1596 
1597 #ifdef XETEX_MAC
1598     CFDictionaryRef attributes = NULL;
1599 
1600     if (fontarea[f] == AAT_FONT_FLAG) {
1601         CTFontRef font;
1602         CGColorRef color;
1603         CGAffineTransform t;
1604         CFNumberRef emboldenNumber;
1605         CGFloat fSize;
1606 
1607         attributes = (CFDictionaryRef) fontlayoutengine[f];
1608         font = CFDictionaryGetValue(attributes, kCTFontAttributeName);
1609 
1610         filename = getFileNameFromCTFont(font, &index);
1611         assert(filename);
1612 
1613         if (CFDictionaryGetValue(attributes, kCTVerticalFormsAttributeName))
1614             flags |= XDV_FLAG_VERTICAL;
1615 
1616         color = (CGColorRef) CFDictionaryGetValue(attributes, kCTForegroundColorAttributeName);
1617         if (color)
1618             rgba = cgColorToRGBA32(color);
1619 
1620         t = CTFontGetMatrix(font);
1621         extend = t.a;
1622         slant = t.c;
1623 
1624         emboldenNumber = CFDictionaryGetValue(attributes, kXeTeXEmboldenAttributeName);
1625         if (emboldenNumber)
1626             CFNumberGetValue(emboldenNumber, kCFNumberFloatType, &embolden);
1627 
1628         fSize = CTFontGetSize(font);
1629         size = D2Fix(fSize);
1630     } else
1631 #endif
1632     if (fontarea[f] == OTGR_FONT_FLAG) {
1633         XeTeXLayoutEngine engine;
1634 
1635         engine = (XeTeXLayoutEngine)fontlayoutengine[f];
1636         fontRef = getFontRef(engine);
1637         filename = getFontFilename(engine, &index);
1638         assert(filename);
1639 
1640         rgba = getRgbValue(engine);
1641         if ((fontflags[f] & FONT_FLAGS_VERTICAL) != 0)
1642             flags |= XDV_FLAG_VERTICAL;
1643 
1644         extend = getExtendFactor(engine);
1645         slant = getSlantFactor(engine);
1646         embolden = getEmboldenFactor(engine);
1647 
1648         size = D2Fix(getPointSize(engine));
1649     } else {
1650         fprintf(stderr, "\n! Internal error: bad native font flag in `make_font_def'\n");
1651         exit(3);
1652     }
1653 
1654     filenameLen = strlen(filename);
1655 
1656     /* parameters after internal font ID:
1657     //  size[4]
1658     //  flags[2]
1659     //  l[1] n[l]
1660     //  if flags & COLORED:
1661     //      c[4]
1662     */
1663 
1664     fontDefLength
1665         = 4 /* size */
1666         + 2 /* flags */
1667         + 1 /* name length */
1668         + filenameLen
1669         + 4 /* face index */;
1670 
1671     if ((fontflags[f] & FONT_FLAGS_COLORED) != 0) {
1672         fontDefLength += 4; /* 32-bit RGBA value */
1673         flags |= XDV_FLAG_COLORED;
1674     }
1675 
1676     if (extend != 1.0) {
1677         fontDefLength += 4;
1678         flags |= XDV_FLAG_EXTEND;
1679     }
1680     if (slant != 0.0) {
1681         fontDefLength += 4;
1682         flags |= XDV_FLAG_SLANT;
1683     }
1684     if (embolden != 0.0) {
1685         fontDefLength += 4;
1686         flags |= XDV_FLAG_EMBOLDEN;
1687     }
1688 
1689     if (fontDefLength > xdvBufSize) {
1690         if (xdvbuffer != NULL)
1691             free(xdvbuffer);
1692         xdvBufSize = ((fontDefLength / 1024) + 1) * 1024;
1693         xdvbuffer = (char*) xmalloc(xdvBufSize);
1694     }
1695     cp = xdvbuffer;
1696 
1697     *(Fixed*)cp = SWAP32(size);
1698     cp += 4;
1699 
1700     *(uint16_t*)cp = SWAP16(flags);
1701     cp += 2;
1702 
1703     *(uint8_t*)cp = filenameLen;
1704     cp += 1;
1705     memcpy(cp, filename, filenameLen);
1706     cp += filenameLen;
1707 
1708     *(uint32_t*)cp = SWAP32(index);
1709     cp += 4;
1710 
1711     if ((fontflags[f] & FONT_FLAGS_COLORED) != 0) {
1712         *(uint32_t*)cp = SWAP32(rgba);
1713         cp += 4;
1714     }
1715 
1716     if (flags & XDV_FLAG_EXTEND) {
1717         Fixed f = D2Fix(extend);
1718         *(uint32_t*)(cp) = SWAP32(f);
1719         cp += 4;
1720     }
1721     if (flags & XDV_FLAG_SLANT) {
1722         Fixed f = D2Fix(slant);
1723         *(uint32_t*)(cp) = SWAP32(f);
1724         cp += 4;
1725     }
1726     if (flags & XDV_FLAG_EMBOLDEN) {
1727         Fixed f = D2Fix(embolden);
1728         *(uint32_t*)(cp) = SWAP32(f);
1729         cp += 4;
1730     }
1731 
1732     free((char*) filename);
1733 
1734     return fontDefLength;
1735 }
1736 
1737 int
applymapping(void * pCnv,const uint16_t * txtPtr,int txtLen)1738 applymapping(void* pCnv, const uint16_t* txtPtr, int txtLen)
1739 {
1740     TECkit_Converter cnv = (TECkit_Converter)pCnv;
1741     UInt32 inUsed, outUsed;
1742     TECkit_Status status;
1743     static UInt32 outLength = 0;
1744 
1745     /* allocate outBuffer if not big enough */
1746     if (outLength < txtLen * sizeof(UniChar) + 32) {
1747         if (mappedtext != 0)
1748             free(mappedtext);
1749         outLength = txtLen * sizeof(UniChar) + 32;
1750         mappedtext = xmalloc(outLength);
1751     }
1752 
1753     /* try the mapping */
1754 retry:
1755     status = TECkit_ConvertBuffer(cnv,
1756             (Byte*)txtPtr, txtLen * sizeof(UniChar), &inUsed,
1757             (Byte*)mappedtext, outLength, &outUsed, true);
1758 
1759     switch (status) {
1760         case kStatus_NoError:
1761             txtPtr = (const UniChar*)mappedtext;
1762             return outUsed / sizeof(UniChar);
1763 
1764         case kStatus_OutputBufferFull:
1765             outLength += (txtLen * sizeof(UniChar)) + 32;
1766             free(mappedtext);
1767             mappedtext = xmalloc(outLength);
1768             goto retry;
1769 
1770         default:
1771             return 0;
1772     }
1773 }
1774 
1775 static void
snap_zone(scaled * value,scaled snap_value,scaled fuzz)1776 snap_zone(scaled* value, scaled snap_value, scaled fuzz)
1777 {
1778     scaled difference = *value - snap_value;
1779     if (difference <= fuzz && difference >= -fuzz)
1780         *value = snap_value;
1781 }
1782 
1783 void
getnativecharheightdepth(integer font,integer ch,scaled * height,scaled * depth)1784 getnativecharheightdepth(integer font, integer ch, scaled* height, scaled* depth)
1785 {
1786 #define QUAD(f)         fontinfo[6+parambase[f]].cint
1787 #define X_HEIGHT(f)     fontinfo[5+parambase[f]].cint
1788 #define CAP_HEIGHT(f)   fontinfo[8+parambase[f]].cint
1789 
1790     float ht = 0.0;
1791     float dp = 0.0;
1792     Fixed fuzz;
1793 
1794 #ifdef XETEX_MAC
1795     if (fontarea[font] == AAT_FONT_FLAG) {
1796         CFDictionaryRef attributes = (CFDictionaryRef)(fontlayoutengine[font]);
1797         int gid = MapCharToGlyph_AAT(attributes, ch);
1798         GetGlyphHeightDepth_AAT(attributes, gid, &ht, &dp);
1799     } else
1800 #endif
1801     if (fontarea[font] == OTGR_FONT_FLAG) {
1802         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font];
1803         int gid = mapCharToGlyph(engine, ch);
1804         getGlyphHeightDepth(engine, gid, &ht, &dp);
1805     } else {
1806         fprintf(stderr, "\n! Internal error: bad native font flag in `get_native_char_height_depth`\n");
1807         exit(3);
1808     }
1809 
1810     *height = D2Fix(ht);
1811     *depth = D2Fix(dp);
1812 
1813     /* snap to "known" zones for baseline, x-height, cap-height if within 4% of em-size */
1814     fuzz = QUAD(font) / 25;
1815     snap_zone(depth, 0, fuzz);
1816     snap_zone(height, 0, fuzz);
1817     snap_zone(height, X_HEIGHT(font), fuzz);
1818     snap_zone(height, CAP_HEIGHT(font), fuzz);
1819 }
1820 
1821 scaled
getnativecharht(integer f,integer c)1822 getnativecharht(integer f, integer c)
1823 {
1824     scaled h, d;
1825     getnativecharheightdepth(f, c, &h, &d);
1826     return h;
1827 }
1828 
1829 scaled
getnativechardp(integer f,integer c)1830 getnativechardp(integer f, integer c)
1831 {
1832     scaled h, d;
1833     getnativecharheightdepth(f, c, &h, &d);
1834     return d;
1835 }
1836 
1837 void
getnativecharsidebearings(integer font,integer ch,scaled * lsb,scaled * rsb)1838 getnativecharsidebearings(integer font, integer ch, scaled* lsb, scaled* rsb)
1839 {
1840     float l, r;
1841 
1842 #ifdef XETEX_MAC
1843     if (fontarea[font] == AAT_FONT_FLAG) {
1844         CFDictionaryRef attributes = (CFDictionaryRef)(fontlayoutengine[font]);
1845         int gid = MapCharToGlyph_AAT(attributes, ch);
1846         GetGlyphSidebearings_AAT(attributes, gid, &l, &r);
1847     } else
1848 #endif
1849     if (fontarea[font] == OTGR_FONT_FLAG) {
1850         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font];
1851         int gid = mapCharToGlyph(engine, ch);
1852         getGlyphSidebearings(engine, gid, &l, &r);
1853     } else {
1854         fprintf(stderr, "\n! Internal error: bad native font flag in `get_native_char_side_bearings'\n");
1855         exit(3);
1856     }
1857 
1858     *lsb = D2Fix(l);
1859     *rsb = D2Fix(r);
1860 }
1861 
1862 scaled
getglyphbounds(integer font,integer edge,integer gid)1863 getglyphbounds(integer font, integer edge, integer gid)
1864 {
1865 /* edge codes 1,2,3,4 => L T R B */
1866     float a, b;
1867 
1868 #ifdef XETEX_MAC
1869     if (fontarea[font] == AAT_FONT_FLAG) {
1870         CFDictionaryRef attributes = (CFDictionaryRef)(fontlayoutengine[font]);
1871         if (edge & 1)
1872             GetGlyphSidebearings_AAT(attributes, gid, &a, &b);
1873         else
1874             GetGlyphHeightDepth_AAT(attributes, gid, &a, &b);
1875     } else
1876 #endif
1877     if (fontarea[font] == OTGR_FONT_FLAG) {
1878         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font];
1879         if (edge & 1)
1880             getGlyphSidebearings(engine, gid, &a, &b);
1881         else
1882             getGlyphHeightDepth(engine, gid, &a, &b);
1883     } else {
1884         fprintf(stderr, "\n! Internal error: bad native font flag in `get_glyph_bounds'\n");
1885         exit(3);
1886     }
1887     return D2Fix((edge <= 2) ? a : b);
1888 }
1889 
1890 scaled
getnativecharic(integer f,integer c)1891 getnativecharic(integer f, integer c)
1892 {
1893     scaled lsb, rsb;
1894     getnativecharsidebearings(f, c, &lsb, &rsb);
1895     if (rsb < 0)
1896         return fontletterspace[f] - rsb;
1897     else
1898         return fontletterspace[f];
1899 }
1900 
1901 scaled
getnativecharwd(integer f,integer c)1902 getnativecharwd(integer f, integer c)
1903 {
1904     scaled wd = 0;
1905 #ifdef XETEX_MAC
1906     if (fontarea[f] == AAT_FONT_FLAG) {
1907         CFDictionaryRef attributes = (CFDictionaryRef)(fontlayoutengine[f]);
1908         int gid = MapCharToGlyph_AAT(attributes, c);
1909         wd = D2Fix(GetGlyphWidth_AAT(attributes, gid));
1910     } else
1911 #endif
1912     if (fontarea[f] == OTGR_FONT_FLAG) {
1913         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f];
1914         int gid = mapCharToGlyph(engine, c);
1915         wd = D2Fix(getGlyphWidthFromEngine(engine, gid));
1916     } else {
1917         fprintf(stderr, "\n! Internal error: bad native font flag in `get_native_char_wd'\n");
1918         exit(3);
1919     }
1920     return wd;
1921 }
1922 
1923 uint16_t
get_native_glyph(void * pNode,unsigned index)1924 get_native_glyph(void* pNode, unsigned index)
1925 {
1926     memoryword* node = (memoryword*)pNode;
1927     FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
1928     uint16_t* glyphIDs = (uint16_t*)(locations + native_glyph_count(node));
1929     if (index >= native_glyph_count(node))
1930         return 0;
1931     else
1932         return glyphIDs[index];
1933 }
1934 
1935 void
store_justified_native_glyphs(void * node)1936 store_justified_native_glyphs(void* node)
1937 {
1938 #ifdef XETEX_MAC /* this is only called for AAT fonts */
1939     (void)DoAATLayout(node, 1);
1940 #endif
1941 }
1942 
1943 void
measure_native_node(void * pNode,int use_glyph_metrics)1944 measure_native_node(void* pNode, int use_glyph_metrics)
1945 {
1946     memoryword* node = (memoryword*)pNode;
1947     int txtLen = native_length(node);
1948     uint16_t* txtPtr = (uint16_t*)(node + native_node_size);
1949 
1950     unsigned f = native_font(node);
1951 
1952 #ifdef XETEX_MAC
1953     if (fontarea[f] == AAT_FONT_FLAG) {
1954         /* we're using this font in AAT mode, so fontlayoutengine[f] is actually a CFDictionaryRef */
1955         DoAATLayout(node, 0);
1956     } else
1957 #endif
1958     if (fontarea[f] == OTGR_FONT_FLAG) {
1959         /* using this font in OT Layout mode, so fontlayoutengine[f] is actually a XeTeXLayoutEngine */
1960 
1961         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)(fontlayoutengine[f]);
1962 
1963         FixedPoint* locations;
1964         uint16_t* glyphIDs;
1965         Fixed* glyphAdvances;
1966         int totalGlyphCount = 0;
1967 
1968         /* need to find direction runs within the text, and call layoutChars separately for each */
1969 
1970         UBiDiDirection dir;
1971         void* glyph_info = 0;
1972         static FloatPoint* positions = 0;
1973         static float* advances = 0;
1974         static uint32_t* glyphs = 0;
1975 
1976         UBiDi* pBiDi = ubidi_open();
1977 
1978         UErrorCode errorCode = U_ZERO_ERROR;
1979         ubidi_setPara(pBiDi, (const UChar*) txtPtr, txtLen, getDefaultDirection(engine), NULL, &errorCode);
1980 
1981         dir = ubidi_getDirection(pBiDi);
1982         if (dir == UBIDI_MIXED) {
1983             /* we actually do the layout twice here, once to count glyphs and then again to get them;
1984                which is inefficient, but i figure that MIXED is a relatively rare occurrence, so i can't be
1985                bothered to deal with the memory reallocation headache of doing it differently
1986             */
1987             int nRuns = ubidi_countRuns(pBiDi, &errorCode);
1988             double width = 0;
1989             int i, runIndex;
1990             int32_t logicalStart, length;
1991             for (runIndex = 0; runIndex < nRuns; ++runIndex) {
1992                 dir = ubidi_getVisualRun(pBiDi, runIndex, &logicalStart, &length);
1993                 totalGlyphCount += layoutChars(engine, txtPtr, logicalStart, length, txtLen, (dir == UBIDI_RTL));
1994             }
1995 
1996             if (totalGlyphCount > 0) {
1997                 double x, y;
1998                 glyph_info = xcalloc(totalGlyphCount, native_glyph_info_size);
1999                 locations = (FixedPoint*)glyph_info;
2000                 glyphIDs = (uint16_t*)(locations + totalGlyphCount);
2001                 glyphAdvances = (Fixed*) xcalloc(totalGlyphCount, sizeof(Fixed));
2002                 totalGlyphCount = 0;
2003 
2004                 x = y = 0.0;
2005                 for (runIndex = 0; runIndex < nRuns; ++runIndex) {
2006                     int nGlyphs;
2007                     dir = ubidi_getVisualRun(pBiDi, runIndex, &logicalStart, &length);
2008                     nGlyphs = layoutChars(engine, txtPtr, logicalStart, length, txtLen,
2009                                             (dir == UBIDI_RTL));
2010 
2011                     glyphs = (uint32_t*) xcalloc(nGlyphs, sizeof(uint32_t));
2012                     positions = (FloatPoint*) xcalloc(nGlyphs + 1, sizeof(FloatPoint));
2013                     advances = (float*) xcalloc(nGlyphs, sizeof(float));
2014 
2015                     getGlyphs(engine, glyphs);
2016                     getGlyphAdvances(engine, advances);
2017                     getGlyphPositions(engine, positions);
2018 
2019                     for (i = 0; i < nGlyphs; ++i) {
2020                         glyphIDs[totalGlyphCount] = glyphs[i];
2021                         locations[totalGlyphCount].x = D2Fix(positions[i].x + x);
2022                         locations[totalGlyphCount].y = D2Fix(positions[i].y + y);
2023                         glyphAdvances[totalGlyphCount] = D2Fix(advances[i]);
2024                         ++totalGlyphCount;
2025                     }
2026                     x += positions[nGlyphs].x;
2027                     y += positions[nGlyphs].y;
2028 
2029                     free(glyphs);
2030                     free(positions);
2031                     free(advances);
2032                 }
2033                 width = x;
2034             }
2035 
2036             node_width(node) = D2Fix(width);
2037             native_glyph_count(node) = totalGlyphCount;
2038             native_glyph_info_ptr(node) = glyph_info;
2039         } else {
2040             double width = 0;
2041             totalGlyphCount = layoutChars(engine, txtPtr, 0, txtLen, txtLen, (dir == UBIDI_RTL));
2042 
2043             glyphs = (uint32_t*) xcalloc(totalGlyphCount, sizeof(uint32_t));
2044             positions = (FloatPoint*) xcalloc(totalGlyphCount + 1, sizeof(FloatPoint));
2045             advances = (float*) xcalloc(totalGlyphCount, sizeof(float));
2046 
2047             getGlyphs(engine, glyphs);
2048             getGlyphAdvances(engine, advances);
2049             getGlyphPositions(engine, positions);
2050 
2051             if (totalGlyphCount > 0) {
2052                 int i;
2053                 glyph_info = xcalloc(totalGlyphCount, native_glyph_info_size);
2054                 locations = (FixedPoint*)glyph_info;
2055                 glyphIDs = (uint16_t*)(locations + totalGlyphCount);
2056                 glyphAdvances = (Fixed*) xcalloc(totalGlyphCount, sizeof(Fixed));
2057                 for (i = 0; i < totalGlyphCount; ++i) {
2058                     glyphIDs[i] = glyphs[i];
2059                     glyphAdvances[i] = D2Fix(advances[i]);
2060                     locations[i].x = D2Fix(positions[i].x);
2061                     locations[i].y = D2Fix(positions[i].y);
2062                 }
2063                 width = D2Fix(positions[totalGlyphCount].x);
2064             }
2065 
2066             node_width(node) = width;
2067             native_glyph_count(node) = totalGlyphCount;
2068             native_glyph_info_ptr(node) = glyph_info;
2069 
2070             free(glyphs);
2071             free(positions);
2072             free(advances);
2073         }
2074 
2075         ubidi_close(pBiDi);
2076 
2077 
2078         if (fontletterspace[f] != 0) {
2079             Fixed lsDelta = 0;
2080             Fixed lsUnit = fontletterspace[f];
2081             int i;
2082             for (i = 0; i < totalGlyphCount; ++i) {
2083                 if (glyphAdvances[i] == 0 && lsDelta != 0)
2084                     lsDelta -= lsUnit;
2085                 locations[i].x += lsDelta;
2086                 lsDelta += lsUnit;
2087             }
2088             if (lsDelta != 0) {
2089                 lsDelta -= lsUnit;
2090                 node_width(node) += lsDelta;
2091             }
2092         }
2093         free(glyphAdvances);
2094     } else {
2095         fprintf(stderr, "\n! Internal error: bad native font flag in `measure_native_node'\n");
2096         exit(3);
2097     }
2098 
2099     if (use_glyph_metrics == 0 || native_glyph_count(node) == 0) {
2100         /* for efficiency, height and depth are the font's ascent/descent,
2101             not true values based on the actual content of the word,
2102             unless use_glyph_metrics is non-zero */
2103         node_height(node) = heightbase[f];
2104         node_depth(node) = depthbase[f];
2105     } else {
2106         /* this iterates over the glyph data whether it comes from AAT or OT layout */
2107         FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
2108         uint16_t* glyphIDs = (uint16_t*)(locations + native_glyph_count(node));
2109         float yMin = 65536.0;
2110         float yMax = -65536.0;
2111         int i;
2112         for (i = 0; i < native_glyph_count(node); ++i) {
2113             float ht, dp;
2114             float y = Fix2D(-locations[i].y); /* NB negative is upwards in locations[].y! */
2115 
2116             GlyphBBox bbox;
2117             if (getCachedGlyphBBox(f, glyphIDs[i], &bbox) == 0) {
2118 #ifdef XETEX_MAC
2119                 if (fontarea[f] == AAT_FONT_FLAG)
2120                     GetGlyphBBox_AAT((CFDictionaryRef)(fontlayoutengine[f]), glyphIDs[i], &bbox);
2121                 else
2122 #endif
2123                 if (fontarea[f] == OTGR_FONT_FLAG)
2124                     getGlyphBounds((XeTeXLayoutEngine)(fontlayoutengine[f]), glyphIDs[i], &bbox);
2125 
2126                 cacheGlyphBBox(f, glyphIDs[i], &bbox);
2127             }
2128 
2129             ht = bbox.yMax;
2130             dp = -bbox.yMin;
2131 
2132             if (y + ht > yMax)
2133                 yMax = y + ht;
2134             if (y - dp < yMin)
2135                 yMin = y - dp;
2136         }
2137         node_height(node) = D2Fix(yMax);
2138         node_depth(node) = -D2Fix(yMin);
2139     }
2140 }
2141 
2142 Fixed
get_native_italic_correction(void * pNode)2143 get_native_italic_correction(void* pNode)
2144 {
2145     memoryword* node = (memoryword*) pNode;
2146     unsigned f = native_font(node);
2147     unsigned n = native_glyph_count(node);
2148     if (n > 0) {
2149         FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
2150         uint16_t* glyphIDs = (uint16_t*)(locations + n);
2151 
2152 #ifdef XETEX_MAC
2153         if (fontarea[f] == AAT_FONT_FLAG)
2154             return D2Fix(GetGlyphItalCorr_AAT((CFDictionaryRef)(fontlayoutengine[f]), glyphIDs[n-1]))
2155                     + fontletterspace[f];
2156 #endif
2157         if (fontarea[f] == OTGR_FONT_FLAG)
2158             return D2Fix(getGlyphItalCorr((XeTeXLayoutEngine)(fontlayoutengine[f]), glyphIDs[n-1]))
2159                     + fontletterspace[f];
2160     }
2161 
2162     return 0;
2163 }
2164 
2165 
2166 Fixed
get_native_glyph_italic_correction(void * pNode)2167 get_native_glyph_italic_correction(void* pNode)
2168 {
2169     memoryword* node = (memoryword*) pNode;
2170     uint16_t gid = native_glyph(node);
2171     unsigned f = native_font(node);
2172 
2173 #ifdef XETEX_MAC
2174     if (fontarea[f] == AAT_FONT_FLAG)
2175         return D2Fix(GetGlyphItalCorr_AAT((CFDictionaryRef)(fontlayoutengine[f]), gid));
2176 #endif
2177     if (fontarea[f] == OTGR_FONT_FLAG)
2178         return D2Fix(getGlyphItalCorr((XeTeXLayoutEngine)(fontlayoutengine[f]), gid));
2179 
2180     return 0;   /* can't actually happen */
2181 }
2182 
2183 void
measure_native_glyph(void * pNode,int use_glyph_metrics)2184 measure_native_glyph(void* pNode, int use_glyph_metrics)
2185 {
2186     memoryword* node = (memoryword*) pNode;
2187     uint16_t gid = native_glyph(node);
2188     unsigned f = native_font(node);
2189 
2190     float ht = 0.0;
2191     float dp = 0.0;
2192 
2193 #ifdef XETEX_MAC
2194     if (fontarea[f] == AAT_FONT_FLAG) {
2195         CFDictionaryRef attributes = (CFDictionaryRef)(fontlayoutengine[f]);
2196         node_width(node) = D2Fix(GetGlyphWidth_AAT(attributes, gid));
2197         if (use_glyph_metrics)
2198             GetGlyphHeightDepth_AAT(attributes, gid, &ht, &dp);
2199     } else
2200 #endif
2201     if (fontarea[f] == OTGR_FONT_FLAG) {
2202         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[f];
2203         XeTeXFont fontInst = getFont(engine);
2204         node_width(node) = D2Fix(getGlyphWidth(fontInst, gid));
2205         if (use_glyph_metrics)
2206             getGlyphHeightDepth(engine, gid, &ht, &dp);
2207     } else {
2208         fprintf(stderr, "\n! Internal error: bad native font flag in `measure_native_glyph'\n");
2209         exit(3);
2210     }
2211 
2212     if (use_glyph_metrics) {
2213         node_height(node) = D2Fix(ht);
2214         node_depth(node) = D2Fix(dp);
2215     } else {
2216         node_height(node) = heightbase[f];
2217         node_depth(node) = depthbase[f];
2218     }
2219 }
2220 
2221 integer
mapchartoglyph(integer font,integer ch)2222 mapchartoglyph(integer font, integer ch)
2223 {
2224     if (ch > 0x10ffff || ((ch >= 0xd800) && (ch <= 0xdfff)))
2225         return 0;
2226 #ifdef XETEX_MAC
2227     if (fontarea[font] == AAT_FONT_FLAG)
2228         return MapCharToGlyph_AAT((CFDictionaryRef)(fontlayoutengine[font]), ch);
2229     else
2230 #endif
2231     if (fontarea[font] == OTGR_FONT_FLAG)
2232         return mapCharToGlyph((XeTeXLayoutEngine)(fontlayoutengine[font]), ch);
2233     else {
2234         fprintf(stderr, "\n! Internal error: bad native font flag in `map_char_to_glyph'\n");
2235         exit(3);
2236     }
2237 }
2238 
2239 integer
mapglyphtoindex(integer font)2240 mapglyphtoindex(integer font)
2241     /* glyph name is at nameoffile+1 */
2242 {
2243 #ifdef XETEX_MAC
2244     if (fontarea[font] == AAT_FONT_FLAG)
2245         return MapGlyphToIndex_AAT((CFDictionaryRef)(fontlayoutengine[font]), (const char*)nameoffile + 1);
2246     else
2247 #endif
2248     if (fontarea[font] == OTGR_FONT_FLAG)
2249         return mapGlyphToIndex((XeTeXLayoutEngine)(fontlayoutengine[font]), (const char*)nameoffile + 1);
2250     else {
2251         fprintf(stderr, "\n! Internal error: bad native font flag in `map_glyph_to_index'\n");
2252         exit(3);
2253     }
2254 }
2255 
2256 integer
getfontcharrange(integer font,int first)2257 getfontcharrange(integer font, int first)
2258 {
2259 #ifdef XETEX_MAC
2260     if (fontarea[font] == AAT_FONT_FLAG)
2261         return GetFontCharRange_AAT((CFDictionaryRef)(fontlayoutengine[font]), first);
2262     else
2263 #endif
2264     if (fontarea[font] == OTGR_FONT_FLAG)
2265         return getFontCharRange((XeTeXLayoutEngine)(fontlayoutengine[font]), first);
2266     else {
2267         fprintf(stderr, "\n! Internal error: bad native font flag in `get_font_char_range'\n");
2268         exit(3);
2269     }
2270 }
2271 
D2Fix(double d)2272 Fixed D2Fix(double d)
2273 {
2274     Fixed rval = (int)(d * 65536.0 + 0.5);
2275     return rval;
2276 }
2277 
Fix2D(Fixed f)2278 double Fix2D(Fixed f)
2279 {
2280     double rval = f / 65536.0;
2281     return rval;
2282 }
2283 
2284 /* these are here, not XeTeX_mac.c, because we need stubs on other platforms */
2285 void
aatgetfontmetrics(CFDictionaryRef attributes,integer * ascent,integer * descent,integer * xheight,integer * capheight,integer * slant)2286 aatgetfontmetrics(CFDictionaryRef attributes, integer* ascent, integer* descent, integer* xheight, integer* capheight, integer* slant)
2287 {
2288 #ifdef XETEX_MAC
2289     CTFontRef font = fontFromAttributes(attributes);
2290 
2291     *ascent = D2Fix(CTFontGetAscent(font));
2292     *descent = D2Fix(CTFontGetDescent(font));
2293     *xheight = D2Fix(CTFontGetXHeight(font));
2294     *capheight = D2Fix(CTFontGetCapHeight(font));
2295     *slant = D2Fix(tan(-CTFontGetSlantAngle(font) * M_PI / 180.0));
2296 #endif
2297 }
2298 
2299 int
aatfontget(int what,CFDictionaryRef attributes)2300 aatfontget(int what, CFDictionaryRef attributes)
2301 {
2302     int rval = -1;
2303 
2304 #ifdef XETEX_MAC
2305     CTFontRef font = fontFromAttributes(attributes);
2306     CFArrayRef list;
2307 
2308     switch (what) {
2309         case XeTeX_count_glyphs:
2310             rval = CTFontGetGlyphCount(font);
2311             break;
2312 
2313         case XeTeX_count_features:
2314             list = CTFontCopyFeatures(font);
2315             if (list) {
2316                 rval = CFArrayGetCount(list);
2317                 CFRelease(list);
2318             }
2319             break;
2320     }
2321 #endif
2322     return rval;
2323 }
2324 
2325 int
aatfontget1(int what,CFDictionaryRef attributes,int param)2326 aatfontget1(int what, CFDictionaryRef attributes, int param)
2327 {
2328     int rval = -1;
2329 
2330 #ifdef XETEX_MAC
2331     CTFontRef font = fontFromAttributes(attributes);
2332 
2333     switch (what) {
2334         case XeTeX_feature_code:
2335         {
2336             CFArrayRef features = CTFontCopyFeatures(font);
2337             if (features) {
2338                 if (CFArrayGetCount(features) > param) {
2339                     CFDictionaryRef feature = CFArrayGetValueAtIndex(features, param);
2340                     CFNumberRef identifier = CFDictionaryGetValue(feature, kCTFontFeatureTypeIdentifierKey);
2341                     if (identifier)
2342                         CFNumberGetValue(identifier, kCFNumberIntType, &rval);
2343                 }
2344                 CFRelease(features);
2345             }
2346             break;
2347         }
2348 
2349         case XeTeX_is_exclusive_feature:
2350         {
2351             CFArrayRef features = CTFontCopyFeatures(font);
2352             if (features) {
2353                 CFBooleanRef value;
2354                 CFDictionaryRef feature = findDictionaryInArrayWithIdentifier(features, kCTFontFeatureTypeIdentifierKey, param);
2355                 Boolean found = CFDictionaryGetValueIfPresent(feature, kCTFontFeatureTypeExclusiveKey, (const void **)&value);
2356                 if (found)
2357                     rval = CFBooleanGetValue(value);
2358                 CFRelease(features);
2359             }
2360             break;
2361         }
2362 
2363         case XeTeX_count_selectors:
2364         {
2365             CFArrayRef features = CTFontCopyFeatures(font);
2366             if (features) {
2367                 CFDictionaryRef feature = findDictionaryInArrayWithIdentifier(features, kCTFontFeatureTypeIdentifierKey, param);
2368                 if (feature) {
2369                     CFArrayRef selectors = CFDictionaryGetValue(feature, kCTFontFeatureTypeSelectorsKey);
2370                     if (selectors)
2371                         rval = CFArrayGetCount(selectors);
2372                 }
2373                 CFRelease(features);
2374             }
2375             break;
2376         }
2377     }
2378 #endif
2379 
2380     return rval;
2381 }
2382 
2383 int
aatfontget2(int what,CFDictionaryRef attributes,int param1,int param2)2384 aatfontget2(int what, CFDictionaryRef attributes, int param1, int param2)
2385 {
2386     int rval = -1;
2387 
2388 #ifdef XETEX_MAC
2389     CTFontRef font = fontFromAttributes(attributes);
2390     CFArrayRef features = CTFontCopyFeatures(font);
2391     if (features) {
2392         CFDictionaryRef feature = findDictionaryInArrayWithIdentifier(features, kCTFontFeatureTypeIdentifierKey, param1);
2393         if (feature) {
2394             CFArrayRef selectors = CFDictionaryGetValue(feature, kCTFontFeatureTypeSelectorsKey);
2395             if (selectors) {
2396                 CFDictionaryRef selector;
2397                 switch (what) {
2398                     case XeTeX_selector_code:
2399                         if (CFArrayGetCount(selectors) > param2) {
2400                             CFNumberRef identifier;
2401                             selector = CFArrayGetValueAtIndex(selectors, param2);
2402                             identifier = CFDictionaryGetValue(selector, kCTFontFeatureSelectorIdentifierKey);
2403                             if (identifier)
2404                                 CFNumberGetValue(identifier, kCFNumberIntType, &rval);
2405                         }
2406                         break;
2407                     case XeTeX_is_default_selector:
2408                         selector = findDictionaryInArrayWithIdentifier(selectors, kCTFontFeatureSelectorIdentifierKey, param2);
2409                         if (selector) {
2410                             CFBooleanRef isDefault;
2411                             Boolean found = CFDictionaryGetValueIfPresent(selector, kCTFontFeatureSelectorDefaultKey, (const void **)&isDefault);
2412                             if (found)
2413                                 rval = CFBooleanGetValue(isDefault);
2414                         }
2415                         break;
2416                 }
2417             }
2418         }
2419         CFRelease(features);
2420     }
2421 #endif
2422 
2423     return rval;
2424 }
2425 
2426 int
aatfontgetnamed(int what,CFDictionaryRef attributes)2427 aatfontgetnamed(int what, CFDictionaryRef attributes)
2428 {
2429     int rval = -1;
2430 
2431 #ifdef XETEX_MAC
2432     if (what == XeTeX_find_feature_by_name)
2433         {
2434             CTFontRef font = fontFromAttributes(attributes);
2435             CFArrayRef features = CTFontCopyFeatures(font);
2436             if (features) {
2437                 CFDictionaryRef feature = findDictionaryInArray(features, kCTFontFeatureTypeNameKey,
2438                                                                 (const char*)nameoffile + 1, namelength);
2439                 if (feature) {
2440                     CFNumberRef identifier = CFDictionaryGetValue(feature, kCTFontFeatureTypeIdentifierKey);
2441                     CFNumberGetValue(identifier, kCFNumberIntType, &rval);
2442                 }
2443                 CFRelease(features);
2444             }
2445         }
2446 #endif
2447 
2448     return rval;
2449 }
2450 
2451 int
aatfontgetnamed1(int what,CFDictionaryRef attributes,int param)2452 aatfontgetnamed1(int what, CFDictionaryRef attributes, int param)
2453 {
2454     int rval = -1;
2455 
2456 #ifdef XETEX_MAC
2457     CTFontRef font = fontFromAttributes(attributes);
2458 
2459     if (what == XeTeX_find_selector_by_name) {
2460         CFArrayRef features = CTFontCopyFeatures(font);
2461         if (features) {
2462             CFDictionaryRef feature = findDictionaryInArrayWithIdentifier(features, kCTFontFeatureTypeIdentifierKey, param);
2463             if (feature) {
2464                 CFNumberRef selector = findSelectorByName(feature, (const char*)nameoffile + 1, namelength);
2465                 if (selector)
2466                     CFNumberGetValue(selector, kCFNumberIntType, &rval);
2467             }
2468             CFRelease(features);
2469         }
2470     }
2471 #endif
2472 
2473     return rval;
2474 }
2475 
2476 void
aatprintfontname(int what,CFDictionaryRef attributes,int param1,int param2)2477 aatprintfontname(int what, CFDictionaryRef attributes, int param1, int param2)
2478 {
2479 #ifdef XETEX_MAC
2480     CFStringRef name = NULL;
2481     if (what == XeTeX_feature_name || what == XeTeX_selector_name) {
2482         CTFontRef font = fontFromAttributes(attributes);
2483         CFArrayRef features = CTFontCopyFeatures(font);
2484         if (features) {
2485             CFDictionaryRef feature = findDictionaryInArrayWithIdentifier(features,
2486                                                                           kCTFontFeatureTypeIdentifierKey,
2487                                                                           param1);
2488             if (feature) {
2489                 if (what == XeTeX_feature_name)
2490                     name = CFDictionaryGetValue(feature, kCTFontFeatureTypeNameKey);
2491                 else {
2492                     CFArrayRef selectors = CFDictionaryGetValue(feature, kCTFontFeatureTypeSelectorsKey);
2493                     CFDictionaryRef selector = findDictionaryInArrayWithIdentifier(selectors,
2494                                                                                    kCTFontFeatureSelectorIdentifierKey,
2495                                                                                    param2);
2496                     if (selector)
2497                         name = CFDictionaryGetValue(selector, kCTFontFeatureSelectorNameKey);
2498                 }
2499             }
2500             CFRelease(features);
2501         }
2502     }
2503 
2504     if (name) {
2505         CFIndex len = CFStringGetLength(name);
2506         UniChar* buf = xcalloc(len, sizeof(UniChar));
2507         CFStringGetCharacters(name, CFRangeMake(0, len), buf);
2508         printchars(buf, len);
2509         free(buf);
2510     }
2511 #endif
2512 }
2513 
2514 void
printglyphname(integer font,integer gid)2515 printglyphname(integer font, integer gid)
2516 {
2517     char* s;
2518     int len = 0;
2519 #ifdef XETEX_MAC
2520     if (fontarea[font] == AAT_FONT_FLAG) {
2521         s = GetGlyphNameFromCTFont(fontFromInteger(font), gid, &len);
2522     } else
2523 #endif
2524     if (fontarea[font] == OTGR_FONT_FLAG) {
2525         XeTeXLayoutEngine engine = (XeTeXLayoutEngine)fontlayoutengine[font];
2526         s = (char*)getGlyphName(getFont(engine), gid, &len);
2527     } else {
2528         fprintf(stderr, "\n! Internal error: bad native font flag in `print_glyph_name'\n");
2529         exit(3);
2530     }
2531     while (len-- > 0)
2532         printchar(*s++);
2533 }
2534 
2535 int
u_open_in(unicodefile * f,integer filefmt,const_string fopen_mode,integer mode,integer encodingData)2536 u_open_in(unicodefile* f, integer filefmt, const_string fopen_mode, integer mode, integer encodingData)
2537 {
2538     boolean rval;
2539     *f = (unicodefile) xmalloc(sizeof(UFILE));
2540     (*f)->encodingMode = 0;
2541     (*f)->conversionData = 0;
2542     (*f)->savedChar = -1;
2543     (*f)->skipNextLF = 0;
2544     rval = open_input (&((*f)->f), filefmt, fopen_mode);
2545     if (rval) {
2546         int B1, B2;
2547         if (mode == AUTO) {
2548             /* sniff encoding form */
2549             B1 = GETC((*f)->f);
2550             B2 = GETC((*f)->f);
2551             if (B1 == 0xfe && B2 == 0xff)
2552                 mode = UTF16BE;
2553             else if (B2 == 0xfe && B1 == 0xff)
2554                 mode = UTF16LE;
2555             else if (B1 == 0 && B2 != 0) {
2556                 mode = UTF16BE;
2557                 rewind((*f)->f);
2558             } else if (B2 == 0 && B1 != 0) {
2559                 mode = UTF16LE;
2560                 rewind((*f)->f);
2561             } else if (B1 == 0xef && B2 == 0xbb) {
2562                 int B3 = GETC((*f)->f);
2563                 if (B3 == 0xbf)
2564                     mode = UTF8;
2565             }
2566             if (mode == AUTO) {
2567                 rewind((*f)->f);
2568                 mode = UTF8;
2569             }
2570         }
2571 
2572         setinputfileencoding(*f, mode, encodingData);
2573     }
2574     return rval;
2575 }
2576 
2577 #if defined(WIN32)
2578 static int
Isspace(char c)2579 Isspace(char c)
2580 {
2581     return (c == ' ' || c == '\t');
2582 }
2583 #endif
2584 
2585 int
open_dvi_output(FILE ** fptr)2586 open_dvi_output(FILE** fptr)
2587 {
2588     if (nopdfoutput) {
2589         return open_output(fptr, FOPEN_WBIN_MODE);
2590     } else {
2591         const char *p = (const char*)nameoffile+1;
2592         char    *cmd, *q, *bindir = NULL;
2593         int len = strlen(p);
2594         while (*p)
2595             if (*p++ == '\"')
2596                 ++len;
2597         len += strlen(outputdriver);
2598 #ifndef WIN32
2599         if (!kpse_absolute_p(outputdriver, true))
2600             bindir = kpse_var_value("SELFAUTOLOC");
2601         if (bindir)
2602             len += strlen(bindir) + 1;
2603 #endif
2604         if (output_directory)
2605             len += strlen(output_directory);
2606         len += 10; /* space for -o flag, quotes, NUL */
2607         for (p = (const char*)nameoffile+1; *p; p++)
2608             if (*p == '\"')
2609                 ++len;  /* allow extra space to escape quotes in filename */
2610         cmd = xmalloc(len);
2611 #ifdef WIN32
2612         strcpy(cmd, outputdriver);
2613 #else
2614         if (bindir) {
2615             strcpy(cmd, bindir);
2616             strcat(cmd, "/");
2617             strcat(cmd, outputdriver);
2618         } else {
2619             strcpy(cmd, outputdriver);
2620         }
2621 #endif
2622         strcat(cmd, " -o \"");
2623         if (output_directory) {
2624             len = strlen(output_directory);
2625             if (IS_DIR_SEP(output_directory[len-1]))
2626                 output_directory[len-1] = '\0';
2627             strcat(cmd, output_directory);
2628             strcat(cmd, "/");
2629         }
2630         q = cmd + strlen(cmd);
2631         for (p = (const char*)nameoffile+1; *p; p++) {
2632             if (*p == '\"')
2633                 *q++ = '\\';
2634             *q++ = *p;
2635         }
2636         *q++ = '\"';
2637         *q = '\0';
2638         if (papersize != 0) {
2639             char* cmd2 = concat3(cmd, " -p ", papersize);
2640             free(cmd);
2641             cmd = cmd2;
2642         }
2643         if (output_directory) {
2644             char *fullname = concat3(output_directory, "/", (const char*)nameoffile+1);
2645             free(nameoffile);
2646             namelength = strlen(fullname);
2647             nameoffile = (unsigned char*) xmalloc(namelength + 2);
2648             strcpy((char*)nameoffile+1, fullname);
2649             free(fullname);
2650         }
2651 #if defined(WIN32)
2652         {
2653             wchar_t *tmp1w;
2654             char *p, *pp, *fullcmd, *prgnam;
2655             bindir = kpse_var_value("SELFAUTOLOC");
2656             for(pp = bindir; *pp; pp++) {
2657                 if(*pp == '/') *pp = '\\';
2658             }
2659             pp = cmd;
2660             while(Isspace(*pp))
2661                 pp++;
2662             prgnam = xmalloc(strlen(cmd));
2663             p = prgnam;
2664             while(!Isspace(*pp)) {
2665                 *p++ = *pp++;
2666             }
2667             *p = '\0';
2668             fullcmd = concatn("\"\"", bindir, "\\", prgnam, "\"", pp, "\"", NULL);
2669             tmp1w = get_wstring_from_mbstring(CP_UTF8, (const char *)fullcmd, tmp1w=NULL);
2670             *fptr = _wpopen(tmp1w, L"wb");
2671             free(bindir);
2672             free(prgnam);
2673             free(fullcmd);
2674             free(tmp1w);
2675         }
2676 #else
2677         *fptr = popen(cmd, "w");
2678 #endif
2679         free(cmd);
2680         return (*fptr != 0);
2681     }
2682 }
2683 
2684 int
dviclose(FILE * fptr)2685 dviclose(FILE* fptr)
2686 {
2687     if (nopdfoutput) {
2688         if (fclose(fptr) != 0)
2689             return errno;
2690     } else {
2691         return pclose(fptr);
2692     }
2693     return 0;
2694 }
2695 
2696 int
get_uni_c(UFILE * f)2697 get_uni_c(UFILE* f)
2698 {
2699     int rval;
2700     int c;
2701 #ifdef WIN32
2702     HANDLE hStdin;
2703     DWORD ret;
2704     wint_t wc[1];
2705 #endif
2706 
2707     if (f->savedChar != -1) {
2708         rval = f->savedChar;
2709         f->savedChar = -1;
2710         return rval;
2711     }
2712 
2713     switch (f->encodingMode) {
2714         case UTF8:
2715             c = rval = GETC(f->f);
2716             if (rval != EOF) {
2717                 uint16_t extraBytes = bytesFromUTF8[rval];
2718                 switch (extraBytes) {   /* note: code falls through cases! */
2719                     case 3: c = GETC(f->f);
2720                         if (c < 0x80 || c >= 0xc0) goto bad_utf8;
2721                         rval <<= 6; rval += c;
2722                     case 2: c = GETC(f->f);
2723                         if (c < 0x80 || c >= 0xc0) goto bad_utf8;
2724                         rval <<= 6; rval += c;
2725                     case 1: c = GETC(f->f);
2726                         if (c < 0x80 || c >= 0xc0) goto bad_utf8;
2727                         rval <<= 6; rval += c;
2728                     case 0:
2729                         break;
2730 
2731                     bad_utf8:
2732                         if (c != EOF)
2733                             UNGETC(c, f->f);
2734                     case 5:
2735                     case 4:
2736                         badutf8warning();
2737                         return 0xfffd;      /* return without adjusting by offsetsFromUTF8 */
2738                 };
2739                 rval -= offsetsFromUTF8[extraBytes];
2740             }
2741             break;
2742 
2743         case UTF16BE:
2744             rval = GETC(f->f);
2745             if (rval != EOF) {
2746                 rval <<= 8;
2747                 rval += GETC(f->f);
2748                 if (rval >= 0xd800 && rval <= 0xdbff) {
2749                     int lo = GETC(f->f);
2750                     lo <<= 8;
2751                     lo += GETC(f->f);
2752                     if (lo >= 0xdc00 && lo <= 0xdfff)
2753                         rval = 0x10000 + (rval - 0xd800) * 0x400 + (lo - 0xdc00);
2754                     else {
2755                         rval = 0xfffd;
2756                         f->savedChar = lo;
2757                     }
2758                 } else if (rval >= 0xdc00 && rval <= 0xdfff)
2759                     rval = 0xfffd;
2760             }
2761             break;
2762 
2763         case UTF16LE:
2764             rval = GETC(f->f);
2765             if (rval != EOF) {
2766                 rval += (GETC(f->f) << 8);
2767                 if (rval >= 0xd800 && rval <= 0xdbff) {
2768                     int lo = GETC(f->f);
2769                     lo += (GETC(f->f) << 8);
2770                     if (lo >= 0xdc00 && lo <= 0xdfff)
2771                         rval = 0x10000 + (rval - 0xd800) * 0x400 + (lo - 0xdc00);
2772                     else {
2773                         rval = 0xfffd;
2774                         f->savedChar = lo;
2775                     }
2776                 } else if (rval >= 0xdc00 && rval <= 0xdfff)
2777                     rval = 0xfffd;
2778             }
2779             break;
2780 
2781 #ifdef WIN32
2782         case WIN32CONSOLE:
2783             hStdin = GetStdHandle(STD_INPUT_HANDLE);
2784             if (ReadConsoleW(hStdin, wc, 1, &ret, NULL) == 0) {
2785                 rval = EOF;
2786                 break;
2787             }
2788             rval = wc[0];
2789             if (rval >= 0xd800 && rval <= 0xdbff) {
2790                 int lo;
2791                 if (ReadConsoleW(hStdin, wc, 1, &ret, NULL) == 0) {
2792                     rval = EOF;
2793                     break;
2794                 }
2795                 lo = wc[0];
2796                 if (lo >= 0xdc00 && lo <= 0xdfff)
2797                     rval = 0x10000 + (rval - 0xd800) * 0x400 + (lo - 0xdc00);
2798                 else {
2799                     rval = 0xfffd;
2800                     f->savedChar = lo;
2801                 }
2802             } else if (rval >= 0xdc00 && rval <= 0xdfff)
2803                 rval = 0xfffd;
2804             break;
2805 #endif
2806 
2807         case RAW:
2808             rval = GETC(f->f);
2809             break;
2810 
2811         default:
2812             /* this can't happen */
2813             fprintf(stderr, "! Internal error---file input mode=%d.\n", f->encodingMode);
2814             uexit(3);
2815     }
2816 
2817     return rval;
2818 }
2819 
2820 void
makeutf16name()2821 makeutf16name()
2822 {
2823     unsigned char* s = nameoffile + 1;
2824     uint32_t rval;
2825     uint16_t* t;
2826     static int name16len = 0;
2827     if (name16len <= namelength) {
2828         if (nameoffile16 != 0)
2829             free(nameoffile16);
2830         name16len = namelength + 10;
2831         nameoffile16 = (uint16_t*) xcalloc(name16len, sizeof(uint16_t));
2832     }
2833     t = nameoffile16;
2834     while (s <= nameoffile + namelength) {
2835         uint16_t extraBytes;
2836         rval = *(s++);
2837         extraBytes = bytesFromUTF8[rval];
2838         switch (extraBytes) {   /* note: code falls through cases! */
2839             case 5: rval <<= 6; if (*s) rval += *(s++);
2840             case 4: rval <<= 6; if (*s) rval += *(s++);
2841             case 3: rval <<= 6; if (*s) rval += *(s++);
2842             case 2: rval <<= 6; if (*s) rval += *(s++);
2843             case 1: rval <<= 6; if (*s) rval += *(s++);
2844             case 0: ;
2845         };
2846         rval -= offsetsFromUTF8[extraBytes];
2847         if (rval > 0xffff) {
2848             rval -= 0x10000;
2849             *(t++) = 0xd800 + rval / 0x0400;
2850             *(t++) = 0xdc00 + rval % 0x0400;
2851         } else {
2852             *(t++) = rval;
2853         }
2854     }
2855     namelength16 = t - nameoffile16;
2856 }
2857 
2858 
get_native_word_cp(void * pNode,int side)2859 integer get_native_word_cp(void* pNode, int side)
2860 {
2861     memoryword* node = (memoryword*)pNode;
2862     FixedPoint* locations = (FixedPoint*)native_glyph_info_ptr(node);
2863     uint16_t* glyphIDs = (uint16_t*)(locations + native_glyph_count(node));
2864     uint16_t glyphCount = native_glyph_count(node);
2865     integer f = native_font(node);
2866     uint16_t actual_glyph;
2867 
2868     if (glyphCount == 0)
2869         return 0;
2870 
2871     switch (side) {
2872     case LEFT_SIDE:
2873         actual_glyph = *glyphIDs;
2874         break;
2875     case RIGHT_SIDE:
2876         actual_glyph = glyphIDs[glyphCount - 1];
2877         break;
2878     default:
2879         assert(0); // we should not reach this point
2880     }
2881     return get_cp_code(f, actual_glyph, side);
2882 }
2883