1 /****************************************************************************\
2  Part of the XeTeX typesetting system
3  Copyright (c) 1994-2008 by SIL International
4  Copyright (c) 2009-2014 by Jonathan Kew
5 
6  SIL Author(s): Jonathan Kew
7 
8 Permission is hereby granted, free of charge, to any person obtaining
9 a copy of this software and associated documentation files (the
10 "Software"), to deal in the Software without restriction, including
11 without limitation the rights to use, copy, modify, merge, publish,
12 distribute, sublicense, and/or sell copies of the Software, and to
13 permit persons to whom the Software is furnished to do so, subject to
14 the following conditions:
15 
16 The above copyright notice and this permission notice shall be
17 included in all copies or substantial portions of the Software.
18 
19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
23 FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
24 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 
27 Except as contained in this notice, the name of the copyright holders
28 shall not be used in advertising or otherwise to promote the sale,
29 use or other dealings in this Software without prior written
30 authorization from the copyright holders.
31 \****************************************************************************/
32 
33 #include <w2c/config.h>
34 
35 #include "XeTeX_web.h"
36 
37 #ifdef XETEX_MAC
38 #include "XeTeXFontMgr_Mac.h"
39 #else
40 #include "XeTeXFontMgr_FC.h"
41 #endif
42 #include "XeTeXFontInst.h"
43 
44 #include <hb-ot.h>
45 
46 // see cpascal.h
47 #define printcstring(STR)        \
48   do {                           \
49     const char* ch_ptr = (STR);  \
50     while (*ch_ptr)              \
51       zprintchar(*(ch_ptr++));    \
52   } while (0)
53 
54 XeTeXFontMgr* XeTeXFontMgr::sFontManager = NULL;
55 char XeTeXFontMgr::sReqEngine = 0;
56 
57 /* use our own fmax function because it seems to be missing on certain platforms
58    (solaris2.9, at least) */
59 static inline double
my_fmax(double x,double y)60 my_fmax(double x, double y)
61 {
62     return (x > y) ? x : y;
63 }
64 
65 XeTeXFontMgr*
GetFontManager()66 XeTeXFontMgr::GetFontManager()
67 {
68     if (sFontManager == NULL) {
69 #ifdef XETEX_MAC
70         sFontManager = new XeTeXFontMgr_Mac;
71 #else
72         sFontManager = new XeTeXFontMgr_FC;
73 #endif
74         sFontManager->initialize();
75     }
76 
77     return sFontManager;
78 }
79 
80 void
Terminate()81 XeTeXFontMgr::Terminate()
82 {
83     if (sFontManager != NULL) {
84         sFontManager->terminate();
85         // we don't actually deallocate the manager, just ask it to clean up
86         // any auxiliary data such as the cocoa pool or freetype/fontconfig stuff
87         // as we still need to access font names after this is called
88     }
89 }
90 
91 PlatformFontRef
findFont(const char * name,char * variant,double ptSize)92 XeTeXFontMgr::findFont(const char* name, char* variant, double ptSize)
93     // ptSize is in TeX points, or negative for 'scaled' factor
94     // "variant" string will be shortened (in-place) by removal of /B and /I if present
95 {
96     std::string nameStr(name);
97     Font* font = NULL;
98     int dsize = 100;
99     loadedfontdesignsize = 655360L;
100 
101     for (int pass = 0; pass < 2; ++pass) {
102         // try full name as given
103         std::map<std::string,Font*>::iterator i = m_nameToFont.find(nameStr);
104         if (i != m_nameToFont.end()) {
105             font = i->second;
106             if (font->opSizeInfo.designSize != 0)
107                 dsize = font->opSizeInfo.designSize;
108             break;
109         }
110 
111         // if there's a hyphen, split there and try Family-Style
112         int hyph = nameStr.find('-');
113         if (hyph > 0 && hyph < nameStr.length() - 1) {
114             std::string family(nameStr.begin(), nameStr.begin() + hyph);
115             std::map<std::string,Family*>::iterator f = m_nameToFamily.find(family);
116             if (f != m_nameToFamily.end()) {
117                 std::string style(nameStr.begin() + hyph + 1, nameStr.end());
118                 i = f->second->styles->find(style);
119                 if (i != f->second->styles->end()) {
120                     font = i->second;
121                     if (font->opSizeInfo.designSize != 0)
122                         dsize = font->opSizeInfo.designSize;
123                     break;
124                 }
125             }
126         }
127 
128         // try as PostScript name
129         i = m_psNameToFont.find(nameStr);
130         if (i != m_psNameToFont.end()) {
131             font = i->second;
132             if (font->opSizeInfo.designSize != 0)
133                 dsize = font->opSizeInfo.designSize;
134             break;
135         }
136 
137         // try for the name as a family name
138         std::map<std::string,Family*>::iterator f = m_nameToFamily.find(nameStr);
139 
140         if (f != m_nameToFamily.end()) {
141             // look for a family member with the "regular" bit set in OS/2
142             int regFonts = 0;
143             for (i = f->second->styles->begin(); i != f->second->styles->end(); ++i)
144                 if (i->second->isReg) {
145                     if (regFonts == 0)
146                         font = i->second;
147                     ++regFonts;
148                 }
149 
150             // families with Ornament or similar fonts may flag those as Regular,
151             // which confuses the search above... so try some known names
152             if (font == NULL || regFonts > 1) {
153                 // try for style "Regular", "Plain", "Normal", "Roman"
154                 i = f->second->styles->find("Regular");
155                 if (i != f->second->styles->end())
156                     font = i->second;
157                 else {
158                     i = f->second->styles->find("Plain");
159                     if (i != f->second->styles->end())
160                         font = i->second;
161                     else {
162                         i = f->second->styles->find("Normal");
163                         if (i != f->second->styles->end())
164                             font = i->second;
165                         else {
166                             i = f->second->styles->find("Roman");
167                             if (i != f->second->styles->end())
168                                 font = i->second;
169                         }
170                     }
171                 }
172             }
173 
174             if (font == NULL) {
175                 // look through the family for the (weight, width, slant) nearest to (80, 100, 0)
176                 font = bestMatchFromFamily(f->second, 80, 100, 0);
177             }
178 
179             if (font != NULL)
180                 break;
181         }
182 
183         if (pass == 0) {
184             // didn't find it in our caches, so do a platform search (may be relatively expensive);
185             // this will update the caches with any fonts that seem to match the name given,
186             // so that the second pass might find it
187             searchForHostPlatformFonts(nameStr);
188         }
189     }
190 
191     if (font == NULL)
192         return 0;
193 
194     Family* parent = font->parent;
195 
196     // if there are variant requests, try to apply them
197     // and delete B, I, and S=... codes from the string, just retain /engine option
198     sReqEngine = 0;
199     bool reqBold = false;
200     bool reqItal = false;
201     if (variant != NULL) {
202         std::string varString;
203         char* cp = variant;
204         while (*cp) {
205             if (strncmp(cp, "AAT", 3) == 0) {
206                 sReqEngine = 'A';
207                 cp += 3;
208                 if (varString.length() > 0 && *(varString.end() - 1) != '/')
209                     varString.append("/");
210                 varString.append("AAT");
211                 goto skip_to_slash;
212             }
213             if (strncmp(cp, "ICU", 3) == 0) { // for backword compatability
214                 sReqEngine = 'O';
215                 cp += 3;
216                 if (varString.length() > 0 && *(varString.end() - 1) != '/')
217                     varString.append("/");
218                 varString.append("OT");
219                 goto skip_to_slash;
220             }
221             if (strncmp(cp, "OT", 2) == 0) {
222                 sReqEngine = 'O';
223                 cp += 2;
224                 if (varString.length() > 0 && *(varString.end() - 1) != '/')
225                     varString.append("/");
226                 varString.append("OT");
227                 goto skip_to_slash;
228             }
229             if (strncmp(cp, "GR", 2) == 0) {
230                 sReqEngine = 'G';
231                 cp += 2;
232                 if (varString.length() > 0 && *(varString.end() - 1) != '/')
233                     varString.append("/");
234                 varString.append("GR");
235                 goto skip_to_slash;
236             }
237             if (*cp == 'S') {
238                 char* start = cp;
239                 ++cp;
240                 if (*cp == '=')
241                     ++cp;
242                 ptSize = 0.0;
243                 while (*cp >= '0' && *cp <= '9') {
244                     ptSize = ptSize * 10 + *cp - '0';
245                     ++cp;
246                 }
247                 if (*cp == '.') {
248                     double dec = 1.0;
249                     ++cp;
250                     while (*cp >= '0' && *cp <= '9') {
251                         dec = dec * 10.0;
252                         ptSize = ptSize + (*cp - '0') / dec;
253                         ++cp;
254                     }
255                 }
256                 goto skip_to_slash;
257             }
258 
259             /* if the code is "B" or "I", we skip putting it in varString */
260             while (1) {
261                 if (*cp == 'B') {
262                     reqBold = true;
263                     ++cp;
264                     continue;
265                 }
266                 if (*cp == 'I') {
267                     reqItal = true;
268                     ++cp;
269                     continue;
270                 }
271                 break;
272             }
273 
274         skip_to_slash:
275             while (*cp && *cp != '/')
276                 ++cp;
277             if (*cp == '/')
278                 ++cp;
279         }
280         strcpy(variant, varString.c_str());
281 
282         std::map<std::string,Font*>::iterator i;
283         if (reqItal) {
284             Font* bestMatch = font;
285             if (font->slant < parent->maxSlant)
286                 // try for a face with more slant
287                 bestMatch = bestMatchFromFamily(parent, font->weight, font->width, parent->maxSlant);
288 
289             if (bestMatch == font && font->slant > parent->minSlant)
290                 // maybe the slant is negated, or maybe this was something like "Times-Italic/I"
291                 bestMatch = bestMatchFromFamily(parent, font->weight, font->width, parent->minSlant);
292 
293             if (parent->minWeight == parent->maxWeight && bestMatch->isBold != font->isBold) {
294                 // try again using the bold flag, as we can't trust weight values
295                 Font* newBest = NULL;
296                 for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
297                     if (i->second->isBold == font->isBold) {
298                         if (newBest == NULL && i->second->isItalic != font->isItalic) {
299                             newBest = i->second;
300                             break;
301                         }
302                     }
303                 }
304                 if (newBest != NULL)
305                     bestMatch = newBest;
306             }
307 
308             if (bestMatch == font) {
309                 // maybe slant values weren't present; try the style bits as a fallback
310                 bestMatch = NULL;
311                 for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
312                     if (i->second->isItalic == !font->isItalic) {
313                         if (parent->minWeight != parent->maxWeight) {
314                             // weight info was available, so try to match that
315                             if (bestMatch == NULL || weightAndWidthDiff(i->second, font) < weightAndWidthDiff(bestMatch, font))
316                                 bestMatch = i->second;
317                         } else {
318                             // no weight info, so try matching style bits
319                             if (bestMatch == NULL && i->second->isBold == font->isBold) {
320                                 bestMatch = i->second;
321                                 break;  // found a match, no need to look further as we can't distinguish!
322                             }
323                         }
324                     }
325                 }
326             }
327             if (bestMatch != NULL)
328                 font = bestMatch;
329         }
330 
331         if (reqBold) {
332             // try for more boldness, with the same width and slant
333             Font* bestMatch = font;
334             if (font->weight < parent->maxWeight) {
335                 // try to increase weight by 1/2 x (max - min), rounding up
336                 bestMatch = bestMatchFromFamily(parent,
337                     font->weight + (parent->maxWeight - parent->minWeight) / 2 + 1,
338                     font->width, font->slant);
339                 if (parent->minSlant == parent->maxSlant) {
340                     // double-check the italic flag, as we can't trust slant values
341                     Font* newBest = NULL;
342                     for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
343                         if (i->second->isItalic == font->isItalic) {
344                             if (newBest == NULL || weightAndWidthDiff(i->second, bestMatch) < weightAndWidthDiff(newBest, bestMatch))
345                                 newBest = i->second;
346                         }
347                     }
348                     if (newBest != NULL)
349                         bestMatch = newBest;
350                 }
351             }
352             if (bestMatch == font && !font->isBold) {
353                 for (i = parent->styles->begin(); i != parent->styles->end(); ++i) {
354                     if (i->second->isItalic == font->isItalic && i->second->isBold) {
355                         bestMatch = i->second;
356                         break;
357                     }
358                 }
359             }
360             font = bestMatch;
361         }
362     }
363 
364     // if there's optical size info, try to apply it
365     if (ptSize < 0.0)
366         ptSize = dsize / 10.0;
367     if (font != NULL && font->opSizeInfo.subFamilyID != 0 && ptSize > 0.0) {
368         ptSize = ptSize * 10.0; // convert to decipoints for comparison with the opSize values
369         double bestMismatch = my_fmax(font->opSizeInfo.minSize - ptSize, ptSize - font->opSizeInfo.maxSize);
370         if (bestMismatch > 0.0) {
371             Font* bestMatch = font;
372             for (std::map<std::string,Font*>::iterator i = parent->styles->begin(); i != parent->styles->end(); ++i) {
373                 if (i->second->opSizeInfo.subFamilyID != font->opSizeInfo.subFamilyID)
374                     continue;
375                 double mismatch = my_fmax(i->second->opSizeInfo.minSize - ptSize, ptSize - i->second->opSizeInfo.maxSize);
376                 if (mismatch < bestMismatch) {
377                     bestMatch = i->second;
378                     bestMismatch = mismatch;
379                 }
380                 if (bestMismatch <= 0.0)
381                     break;
382             }
383             font = bestMatch;
384         }
385     }
386 
387     if (font != NULL && font->opSizeInfo.designSize != 0)
388         loadedfontdesignsize = (font->opSizeInfo.designSize << 16L) / 10;
389 
390     if (gettracingfontsstate() > 0) {
391         begindiagnostic();
392         zprintnl(' ');
393         printcstring("-> ");
394         printcstring(getPlatformFontDesc(font->fontRef).c_str());
395         zenddiagnostic(0);
396     }
397 
398     return font->fontRef;
399 }
400 
401 const char*
getFullName(PlatformFontRef font) const402 XeTeXFontMgr::getFullName(PlatformFontRef font) const
403 {
404     std::map<PlatformFontRef,Font*>::const_iterator i = m_platformRefToFont.find(font);
405     if (i == m_platformRefToFont.end())
406         die("internal error %d in XeTeXFontMgr", 2);
407     if (i->second->m_fullName != NULL)
408         return i->second->m_fullName->c_str();
409     else
410         return i->second->m_psName->c_str();
411 }
412 
413 int
weightAndWidthDiff(const Font * a,const Font * b) const414 XeTeXFontMgr::weightAndWidthDiff(const Font* a, const Font* b) const
415 {
416     if (a->weight == 0 && a->width == 0) {
417         // assume there was no OS/2 info
418         if (a->isBold == b->isBold)
419             return 0;
420         else
421             return 10000;
422     }
423 
424     int widDiff = labs(a->width - b->width);
425     if (widDiff < 10)
426         widDiff *= 50;
427 
428     return labs(a->weight - b->weight) + widDiff;
429 }
430 
431 int
styleDiff(const Font * a,int wt,int wd,int slant) const432 XeTeXFontMgr::styleDiff(const Font* a, int wt, int wd, int slant) const
433 {
434     int widDiff = labs(a->width - wd);
435     if (widDiff < 10)
436         widDiff *= 200;
437 
438     return labs(labs(a->slant) - labs(slant)) * 2 + labs(a->weight - wt) + widDiff;
439 }
440 
441 XeTeXFontMgr::Font*
bestMatchFromFamily(const Family * fam,int wt,int wd,int slant) const442 XeTeXFontMgr::bestMatchFromFamily(const Family* fam, int wt, int wd, int slant) const
443 {
444     Font* bestMatch = NULL;
445     for (std::map<std::string,Font*>::iterator s = fam->styles->begin(); s != fam->styles->end(); ++s)
446         if (bestMatch == NULL || styleDiff(s->second, wt, wd, slant) < styleDiff(bestMatch, wt, wd, slant))
447             bestMatch = s->second;
448     return bestMatch;
449 }
450 
451 const XeTeXFontMgr::OpSizeRec*
getOpSize(XeTeXFont font)452 XeTeXFontMgr::getOpSize(XeTeXFont font)
453 {
454     hb_font_t* hbFont = ((XeTeXFontInst*)font)->getHbFont();
455     if (hbFont != NULL) {
456         hb_face_t* face = hb_font_get_face(hbFont);
457         OpSizeRec* pSizeRec = (OpSizeRec*) xmalloc(sizeof(OpSizeRec));
458 
459         bool ok = hb_ot_layout_get_size_params(face,
460                 &pSizeRec->designSize,
461                 &pSizeRec->subFamilyID,
462                 &pSizeRec->nameCode,
463                 &pSizeRec->minSize,
464                 &pSizeRec->maxSize);
465 
466         if (ok)
467             return pSizeRec;
468 
469         free(pSizeRec);
470         return NULL;
471     }
472 
473     return NULL;
474 }
475 
476 double
getDesignSize(XeTeXFont font)477 XeTeXFontMgr::getDesignSize(XeTeXFont font)
478 {
479     const OpSizeRec* pSizeRec = getOpSize(font);
480     if (pSizeRec != NULL)
481         return pSizeRec->designSize / 10.0;
482     else
483         return 10.0;
484 }
485 
486 void
getOpSizeRecAndStyleFlags(Font * theFont)487 XeTeXFontMgr::getOpSizeRecAndStyleFlags(Font* theFont)
488 {
489     XeTeXFont font = createFont(theFont->fontRef, 655360);
490     XeTeXFontInst* fontInst = (XeTeXFontInst*) font;
491     if (font != 0) {
492         const OpSizeRec* pSizeRec = getOpSize(font);
493         if (pSizeRec != NULL) {
494             theFont->opSizeInfo.designSize = pSizeRec->designSize;
495             if (pSizeRec->subFamilyID == 0
496                 && pSizeRec->nameCode == 0
497                 && pSizeRec->minSize == 0
498                 && pSizeRec->maxSize == 0)
499                 goto done_size; // feature is valid, but no 'size' range
500             theFont->opSizeInfo.subFamilyID = pSizeRec->subFamilyID;
501             theFont->opSizeInfo.nameCode = pSizeRec->nameCode;
502             theFont->opSizeInfo.minSize = pSizeRec->minSize;
503             theFont->opSizeInfo.maxSize = pSizeRec->maxSize;
504         }
505     done_size:
506 
507         const TT_OS2* os2Table = (TT_OS2*) fontInst->getFontTable(ft_sfnt_os2);
508         if (os2Table != NULL) {
509             theFont->weight = os2Table->usWeightClass;
510             theFont->width = os2Table->usWidthClass;
511             uint16_t sel = os2Table->fsSelection;
512             theFont->isReg = (sel & (1 << 6)) != 0;
513             theFont->isBold = (sel & (1 << 5)) != 0;
514             theFont->isItalic = (sel & (1 << 0)) != 0;
515         }
516 
517         const TT_Header* headTable = (TT_Header*) fontInst->getFontTable(ft_sfnt_head);
518         if (headTable != NULL) {
519             uint16_t ms = headTable->Mac_Style;
520             if ((ms & (1 << 0)) != 0)
521                 theFont->isBold = true;
522             if ((ms & (1 << 1)) != 0)
523                 theFont->isItalic = true;
524         }
525 
526         const TT_Postscript* postTable = (const TT_Postscript*) fontInst->getFontTable(ft_sfnt_post);
527         if (postTable != NULL) {
528             theFont->slant = (int)(1000 * (tan(Fix2D(-postTable->italicAngle) * M_PI / 180.0)));
529         }
530         deleteFont(font);
531     }
532 }
533 
534 // append a name but only if it's not already in the list
535 void
appendToList(std::list<std::string> * list,const char * str)536 XeTeXFontMgr::appendToList(std::list<std::string>* list, const char* str)
537 {
538     for (std::list<std::string>::const_iterator i = list->begin(); i != list->end(); ++i)
539         if (*i == str)
540             return;
541     list->push_back(str);
542 }
543 
544 // prepend a name, removing it from later in the list if present
545 void
prependToList(std::list<std::string> * list,const char * str)546 XeTeXFontMgr::prependToList(std::list<std::string>* list, const char* str)
547 {
548     for (std::list<std::string>::iterator i = list->begin(); i != list->end(); ++i)
549         if (*i == str) {
550             list->erase(i);
551             break;
552         }
553     list->push_front(str);
554 }
555 
556 void
addToMaps(PlatformFontRef platformFont,const NameCollection * names)557 XeTeXFontMgr::addToMaps(PlatformFontRef platformFont, const NameCollection* names)
558 {
559     if (m_platformRefToFont.find(platformFont) != m_platformRefToFont.end())
560         return; // this font has already been cached
561 
562     if (names->m_psName.length() == 0)
563         return; // can't use a font that lacks a PostScript name
564 
565     if (m_psNameToFont.find(names->m_psName) != m_psNameToFont.end())
566         return; // duplicates an earlier PS name, so skip
567 
568     Font* thisFont = new Font(platformFont);
569     thisFont->m_psName = new std::string(names->m_psName);
570     getOpSizeRecAndStyleFlags(thisFont);
571 
572     m_psNameToFont[names->m_psName] = thisFont;
573     m_platformRefToFont[platformFont] = thisFont;
574 
575     if (names->m_fullNames.size() > 0)
576         thisFont->m_fullName = new std::string(*(names->m_fullNames.begin()));
577 
578     if (names->m_familyNames.size() > 0)
579         thisFont->m_familyName = new std::string(*(names->m_familyNames.begin()));
580     else
581         thisFont->m_familyName = new std::string(names->m_psName);
582 
583     if (names->m_styleNames.size() > 0)
584         thisFont->m_styleName = new std::string(*(names->m_styleNames.begin()));
585     else
586         thisFont->m_styleName = new std::string;
587 
588     std::list<std::string>::const_iterator i;
589     for (i = names->m_familyNames.begin(); i != names->m_familyNames.end(); ++i) {
590         std::map<std::string,Family*>::iterator iFam = m_nameToFamily.find(*i);
591         Family* family;
592         if (iFam == m_nameToFamily.end()) {
593             family = new Family;
594             m_nameToFamily[*i] = family;
595             family->minWeight = thisFont->weight;
596             family->maxWeight = thisFont->weight;
597             family->minWidth = thisFont->width;
598             family->maxWidth = thisFont->width;
599             family->minSlant = thisFont->slant;
600             family->maxSlant = thisFont->slant;
601         } else {
602             family = iFam->second;
603             if (thisFont->weight < family->minWeight)
604                 family->minWeight = thisFont->weight;
605             if (thisFont->weight > family->maxWeight)
606                 family->maxWeight = thisFont->weight;
607             if (thisFont->width < family->minWidth)
608                 family->minWidth = thisFont->width;
609             if (thisFont->width > family->maxWidth)
610                 family->maxWidth = thisFont->width;
611             if (thisFont->slant < family->minSlant)
612                 family->minSlant = thisFont->slant;
613             if (thisFont->slant > family->maxSlant)
614                 family->maxSlant = thisFont->slant;
615         }
616 
617         if (thisFont->parent == NULL)
618             thisFont->parent = family;
619 
620         // ensure all style names in the family point to thisFont
621         for (std::list<std::string>::const_iterator j = names->m_styleNames.begin(); j != names->m_styleNames.end(); ++j) {
622             std::map<std::string,Font*>::iterator iFont = family->styles->find(*j);
623             if (iFont == family->styles->end())
624                 (*family->styles)[*j] = thisFont;
625 /*
626             else if (iFont->second != thisFont)
627                 fprintf(stderr, "# Font name warning: ambiguous Style \"%s\" in Family \"%s\" (PSNames \"%s\" and \"%s\")\n",
628                             j->c_str(), i->c_str(), iFont->second->m_psName->c_str(), thisFont->m_psName->c_str());
629 */
630         }
631     }
632 
633     for (i = names->m_fullNames.begin(); i != names->m_fullNames.end(); ++i) {
634         std::map<std::string,Font*>::iterator iFont = m_nameToFont.find(*i);
635         if (iFont == m_nameToFont.end())
636             m_nameToFont[*i] = thisFont;
637 /*
638         else if (iFont->second != thisFont)
639             fprintf(stderr, "# Font name warning: ambiguous FullName \"%s\" (PSNames \"%s\" and \"%s\")\n",
640                         i->c_str(), iFont->second->m_psName->c_str(), thisFont->m_psName->c_str());
641 */
642     }
643 }
644 
645 void
die(const char * s,int i) const646 XeTeXFontMgr::die(const char*s, int i) const
647 {
648     fprintf(stderr, s, i);
649     fprintf(stderr, " - exiting\n");
650     exit(3);
651 }
652 
653 void
terminate()654 XeTeXFontMgr::terminate()
655 {
656 }
657 
658