1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "common/archive.h"
23 #include "common/stream.h"
24 #include "common/unzip.h"
25 #include "common/macresman.h"
26 #include "graphics/fonts/bdf.h"
27 #include "graphics/fonts/macfont.h"
28 #include "graphics/fonts/ttf.h"
29
30 #include "graphics/macgui/macwindowmanager.h"
31 #include "graphics/macgui/macfontmanager.h"
32
33 namespace Graphics {
34
35 // Source: Apple IIGS Technical Note #41, "Font Family Numbers"
36 // http://apple2.boldt.ca/?page=til/tn.iigs.041
37 static struct FontProto {
38 int id;
39 Common::Language lang;
40 Common::CodePage encoding;
41 const char *name;
42 } defaultFonts[] = {
43 { 2, Common::UNK_LANG, Common::kMacRoman, "New York" },
44 { 3, Common::UNK_LANG, Common::kMacRoman, "Geneva" },
45 { 4, Common::UNK_LANG, Common::kMacRoman, "Monaco" },
46 { 5, Common::UNK_LANG, Common::kMacRoman, "Venice" },
47 { 6, Common::UNK_LANG, Common::kMacRoman, "London" },
48 { 7, Common::UNK_LANG, Common::kMacRoman, "Athens" },
49 { 8, Common::UNK_LANG, Common::kMacRoman, "San Francisco" },
50 { 9, Common::UNK_LANG, Common::kMacRoman, "Toronto" },
51 { 11, Common::UNK_LANG, Common::kMacRoman, "Cairo" },
52 { 12, Common::UNK_LANG, Common::kMacRoman, "Los Angeles" },
53 { 13, Common::UNK_LANG, Common::kMacRoman, "Zapf Dingbats" },
54 { 14, Common::UNK_LANG, Common::kMacRoman, "Bookman" },
55 { 15, Common::UNK_LANG, Common::kMacRoman, "Helvetica Narrow" },
56 { 16, Common::UNK_LANG, Common::kMacRoman, "Palatino" },
57 { 18, Common::UNK_LANG, Common::kMacRoman, "Zapf Chancery" },
58 { 20, Common::UNK_LANG, Common::kMacRoman, "Times" },
59 { 21, Common::UNK_LANG, Common::kMacRoman, "Helvetica" },
60 { 22, Common::UNK_LANG, Common::kMacRoman, "Courier" },
61 { 23, Common::UNK_LANG, Common::kMacRoman, "Symbol" },
62 { 24, Common::UNK_LANG, Common::kMacRoman, "Taliesin" }, // mobile?
63 { 33, Common::UNK_LANG, Common::kMacRoman, "Avant Garde" },
64 { 34, Common::UNK_LANG, Common::kMacRoman, "New Century Schoolbook" },
65 { 16383, Common::UNK_LANG, Common::kMacRoman, "Chicago" },
66
67 // Japanese (names are Shift JIS encoded)
68 { 16384, Common::JA_JPN, Common::kUtf8, "Osaka" },
69 { 16436, Common::JA_JPN, Common::kUtf8, "Osaka\x81\x7C\x93\x99\x95\x9D" }, // Osaka Mono
70
71 { -1, Common::UNK_LANG, Common::kCodePageInvalid, NULL }
72 };
73
74 struct AliasProto {
75 int id;
76 int aliasForId;
77 const char *name;
78 };
79
80 static AliasProto defaultAliases[] = {
81 // English names for Japanese fonts
82 { 16436, 16436, "OsakaMono" },
83
84 // Missing Japanese fonts
85 // These technically should be separate fonts, not just aliases for Osaka.
86 // However, we don't have a free source for these right now.
87 { 16396, 16384, "\x96\x7B\x96\xBE\x92\xA9\x81\x7C\x82\x6C" }, // Book Mincho - M
88 { 16433, 16436, "\x93\x99\x95\x9D\x83\x53\x83\x56\x83\x62\x83\x4E" }, // Mono Gothic
89 { 16435, 16436, "\x93\x99\x95\x9D\x96\xBE\x92\xA9" }, // Mono Ming
90 { 16640, 16384, "\x92\x86\x83\x53\x83\x56\x83\x62\x83\x4E\x91\xCC" }, // Medium Gothic
91 { 16641, 16384, "\x8D\xD7\x96\xBE\x92\xA9\x91\xCC" }, // Ming
92 { 16700, 16384, "\x95\xBD\x90\xAC\x96\xBE\x92\xA9" }, // Heisei Mincho
93 { 16701, 16384, "\x95\xBD\x90\xAC\x8A\x70\x83\x53\x83\x56\x83\x62\x83\x4E" }, // Heisei Kaku Gothic
94
95 { -1, -1, NULL }
96 };
97
98 static AliasProto latinModeAliases[] = {
99 { 0, 16383, "System" }, // Chicago
100 { 1, 3, "Application" }, // Geneva
101 { -1, -1, NULL }
102 };
103
104 static AliasProto japaneseModeAliases[] = {
105 { 0, 16384, "System" }, // Osaka
106 { 1, 16384, "Application" }, // Osaka
107 { -1, -1, NULL }
108 };
109
110 static const char *const fontStyleSuffixes[] = {
111 "",
112 "Bold",
113 "Italic",
114 "Underline",
115 "Outline",
116 "Shadow",
117 "Condense",
118 "Extend"
119 };
120
parseSlant(const Common::String fontname)121 int parseSlant(const Common::String fontname) {
122 int res = 0;
123
124 for (int i = 1; i < 7; i++)
125 if (fontname.contains(fontStyleSuffixes[i]))
126 res |= (1 << (i - 1));
127
128 return res;
129 }
130
cleanFontName(const Common::String fontname)131 Common::String cleanFontName(const Common::String fontname) {
132 const char *pos;
133 Common::String f = fontname;
134 for (int i = 1; i < 7; i++) {
135 if ((pos = strstr(f.c_str(), fontStyleSuffixes[i])))
136 f = Common::String(f.c_str(), pos);
137 }
138 f.trim();
139
140 return f;
141 }
142
MacFontManager(uint32 mode,Common::Language language)143 MacFontManager::MacFontManager(uint32 mode, Common::Language language) : _mode(mode), _language(language) {
144 for (FontProto *font = defaultFonts; font->name; font++) {
145 if (!_fontInfo.contains(font->id)) {
146 FontInfo *info = new FontInfo;
147 info->lang = font->lang;
148 info->encoding = font->encoding;
149 info->name = font->name;
150 _fontInfo[font->id] = info;
151 }
152 if (!_fontIds.contains(font->name)) {
153 _fontIds[font->name] = font->id;
154 }
155 }
156 for (AliasProto *alias = defaultAliases; alias->name; alias++) {
157 if (!_fontInfo.contains(alias->id)) {
158 FontInfo *info = new FontInfo;
159 info->aliasForId = alias->aliasForId;
160 info->name = alias->name;
161 _fontInfo[alias->id] = info;
162 }
163 if (!_fontIds.contains(alias->name)) {
164 _fontIds[alias->name] = alias->id;
165 }
166 }
167 setLocalizedFonts();
168
169 if (_mode & MacGUIConstants::kWMModeForceBuiltinFonts) {
170 _builtInFonts = true;
171 } else {
172 loadFonts();
173 }
174 _japaneseFontsLoaded = false;
175 }
176
~MacFontManager()177 MacFontManager::~MacFontManager() {
178 for (Common::HashMap<int, FontInfo *>::iterator it = _fontInfo.begin(); it != _fontInfo.end(); it++)
179 delete it->_value;
180 for (Common::HashMap<int, const Graphics::Font *>::iterator it = _uniFonts.begin(); it != _uniFonts.end(); it++)
181 delete it->_value;
182 for (Common::HashMap<Common::String, Common::SeekableReadStream *>::iterator it = _ttfData.begin(); it != _ttfData.end(); it++)
183 delete it->_value;
184 for (Common::HashMap<Common::String, MacFont *>::iterator it = _fontRegistry.begin(); it != _fontRegistry.end(); it++)
185 delete it->_value;
186 for (Common::HashMap<Common::String, MacFontFamily *>::iterator it = _fontFamilies.begin(); it != _fontFamilies.end(); it++)
187 delete it->_value;
188 }
189
setLocalizedFonts()190 void MacFontManager::setLocalizedFonts() {
191 AliasProto *aliases = latinModeAliases;
192 if (_language == Common::JA_JPN) {
193 aliases = japaneseModeAliases;
194 loadJapaneseFonts();
195 }
196 for (AliasProto *alias = aliases; alias->name; alias++) {
197 if (_fontInfo.contains(alias->id)) {
198 // Overwrite the font info that's already registered in case
199 // we're switching languages or something.
200 delete _fontInfo[alias->id];
201 }
202 FontInfo *info = new FontInfo;
203 info->aliasForId = alias->aliasForId;
204 info->name = alias->name;
205 _fontInfo[alias->id] = info;
206 _fontIds[alias->name] = alias->id;
207 }
208 }
209
loadFontsBDF()210 void MacFontManager::loadFontsBDF() {
211 Common::Archive *dat;
212
213 dat = Common::makeZipArchive("classicmacfonts.dat");
214
215 if (!dat) {
216 warning("Could not find classicmacfonts.dat. Falling back to built-in fonts");
217 _builtInFonts = true;
218
219 return;
220 }
221
222 Common::ArchiveMemberList list;
223 dat->listMembers(list);
224
225 for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
226 Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
227
228 Graphics::BdfFont *font = Graphics::BdfFont::loadFont(*stream);
229
230 delete stream;
231
232 Common::String fontName;
233 MacFont *macfont;
234
235 if (font->getFamilyName() && *font->getFamilyName()) {
236 fontName = Common::String::format("%s-%s-%d", font->getFamilyName(), font->getFontSlant(), font->getFontSize());
237
238 macfont = new MacFont(_fontIds.getValOrDefault(font->getFamilyName(), kMacFontNonStandard), font->getFontSize(), parseFontSlant(font->getFontSlant()));
239 } else { // Get it from the file name
240 fontName = (*it)->getName();
241
242 // Trim the .bdf extension
243 for (int i = fontName.size() - 1; i >= 0; --i) {
244 if (fontName[i] == '.') {
245 while ((uint)i < fontName.size()) {
246 fontName.deleteLastChar();
247 }
248 break;
249 }
250 }
251
252 macfont = new MacFont(kMacFontNonStandard);
253 macfont->setName(fontName);
254 }
255
256 FontMan.assignFontToName(fontName, font);
257 //macfont->setFont(font);
258 _fontRegistry.setVal(fontName, macfont);
259
260 debug(2, " %s", fontName.c_str());
261 }
262
263 _builtInFonts = false;
264
265 delete dat;
266 }
267
loadFonts()268 void MacFontManager::loadFonts() {
269 Common::Archive *dat;
270
271 dat = Common::makeZipArchive("classicmacfonts.dat");
272
273 if (!dat) {
274 warning("Could not find classicmacfonts.dat. Falling back to built-in fonts");
275 _builtInFonts = true;
276
277 return;
278 }
279
280 Common::ArchiveMemberList list;
281 dat->listMembers(list);
282
283 for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
284 Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
285
286 loadFonts(stream);
287 }
288
289 _builtInFonts = false;
290
291 delete dat;
292 }
293
loadJapaneseFonts()294 void MacFontManager::loadJapaneseFonts() {
295 if (_japaneseFontsLoaded)
296 return;
297
298 #ifdef USE_FREETYPE2
299 Common::Archive *dat;
300
301 dat = Common::makeZipArchive("japanesemacfonts.dat");
302
303 if (!dat) {
304 warning("Could not find japanesemacfonts.dat");
305 return;
306 }
307
308 Common::ArchiveMemberList list;
309 dat->listMembers(list);
310
311 for (Common::ArchiveMemberList::iterator it = list.begin(); it != list.end(); ++it) {
312 Common::SeekableReadStream *stream = dat->createReadStreamForMember((*it)->getName());
313 Common::String fontName = (*it)->getName();
314
315 // Trim the .ttf extension
316 for (int i = fontName.size() - 1; i >= 0; --i) {
317 if (fontName[i] == '.') {
318 while ((uint)i < fontName.size()) {
319 fontName.deleteLastChar();
320 }
321 break;
322 }
323 }
324
325 _ttfData[fontName + "-0-0"] = stream;
326 }
327
328 delete dat;
329 #else
330 warning("Japanese fonts require FreeType");
331 #endif
332
333 // Set this to true even if we don't have FreeType so we don't spam warnings.
334 _japaneseFontsLoaded = true;
335 }
336
loadFonts(Common::SeekableReadStream * stream)337 void MacFontManager::loadFonts(Common::SeekableReadStream *stream) {
338 Common::MacResManager fontFile;
339
340 if (!fontFile.loadFromMacBinary(*stream))
341 return;
342
343 loadFonts(&fontFile);
344 }
345
loadFonts(const Common::String & fileName)346 void MacFontManager::loadFonts(const Common::String &fileName) {
347 Common::MacResManager fontFile;
348
349 if (!fontFile.open(fileName))
350 return;
351
352 loadFonts(&fontFile);
353 }
354
loadFonts(Common::MacResManager * fontFile)355 void MacFontManager::loadFonts(Common::MacResManager *fontFile) {
356 Common::MacResIDArray fonds = fontFile->getResIDArray(MKTAG('F','O','N','D'));
357 if (fonds.size() > 0) {
358 for (Common::Array<uint16>::iterator iterator = fonds.begin(); iterator != fonds.end(); ++iterator) {
359 Common::SeekableReadStream *fond = fontFile->getResource(MKTAG('F', 'O', 'N', 'D'), *iterator);
360
361 Common::String familyName = fontFile->getResName(MKTAG('F', 'O', 'N', 'D'), *iterator);
362 int familySlant = parseSlant(familyName);
363
364 if (familySlant) {
365 familyName = cleanFontName(familyName);
366 }
367
368 Graphics::MacFontFamily *fontFamily = new MacFontFamily();
369 fontFamily->load(*fond);
370
371 Common::Array<Graphics::MacFontFamily::AsscEntry> *assoc = fontFamily->getAssocTable();
372
373 bool fontFamilyUsed = false;
374
375 for (uint i = 0; i < assoc->size(); i++) {
376 debug(8, "size: %d style: %d id: %d", (*assoc)[i]._fontSize, (*assoc)[i]._fontStyle | familySlant,
377 (*assoc)[i]._fontID);
378
379 Common::SeekableReadStream *fontstream;
380 MacFont *macfont;
381 Graphics::MacFONTFont *font;
382
383 fontstream = fontFile->getResource(MKTAG('N', 'F', 'N', 'T'), (*assoc)[i]._fontID);
384
385 if (!fontstream)
386 fontstream = fontFile->getResource(MKTAG('F', 'O', 'N', 'T'), (*assoc)[i]._fontID);
387
388 #ifdef USE_FREETYPE2
389 if (!fontstream) {
390 // The sfnt resource should be just a copy of a TTF
391 fontstream = fontFile->getResource(MKTAG('s', 'f', 'n', 't'), (*assoc)[i]._fontID);
392 Common::String fontName = Common::String::format("%s-%d-0", familyName.c_str(), (*assoc)[i]._fontStyle | familySlant);
393 _ttfData[fontName] = fontstream;
394 continue;
395 }
396 #endif
397
398 if (!fontstream) {
399 if ((*assoc)[i]._fontSize == 0) {
400 warning("MacFontManager: Detected possible TrueType FontID %d, but no TrueType support detected", (*assoc)[i]._fontID);
401 } else {
402 warning("MacFontManager: Unknown FontId: %d", (*assoc)[i]._fontID);
403 }
404 continue;
405 }
406
407 fontFamilyUsed = true;
408
409 font = new Graphics::MacFONTFont;
410 font->loadFont(*fontstream, fontFamily, (*assoc)[i]._fontSize, (*assoc)[i]._fontStyle | familySlant);
411
412 delete fontstream;
413
414 Common::String fontName = Common::String::format("%s-%d-%d", familyName.c_str(), (*assoc)[i]._fontStyle | familySlant, (*assoc)[i]._fontSize);
415
416 macfont = new MacFont(_fontIds.getValOrDefault(familyName, kMacFontNonStandard), (*assoc)[i]._fontSize, (*assoc)[i]._fontStyle | familySlant);
417
418 FontMan.assignFontToName(fontName, font);
419 macfont->setFont(font, false);
420 _fontRegistry.setVal(fontName, macfont);
421
422 debug(2, " %s", fontName.c_str());
423 }
424
425 delete fond;
426
427 if (fontFamilyUsed)
428 _fontFamilies[familyName] = fontFamily;
429 else
430 delete fontFamily;
431 }
432 }
433 }
434
getFont(MacFont macFont)435 const Font *MacFontManager::getFont(MacFont macFont) {
436 Common::String name;
437 const Font *font = 0;
438
439 int aliasForId = getFontAliasForId(macFont.getId());
440 if (aliasForId > -1) {
441 macFont.setId(aliasForId);
442 }
443
444 if (!_builtInFonts) {
445 Common::Language lang = getFontLanguage(macFont.getId());
446 if (lang == Common::JA_JPN && !_japaneseFontsLoaded) {
447 loadJapaneseFonts();
448 }
449
450 if (macFont.getName().empty()) {
451 name = getFontName(macFont.getId(), macFont.getSize(), macFont.getSlant());
452 macFont.setName(name);
453 }
454
455 if (!_fontRegistry.contains(macFont.getName())) {
456 // Let's try to generate name
457 if (macFont.getSlant() != kMacFontRegular) {
458 name = getFontName(macFont.getId(), macFont.getSize(), macFont.getSlant(), true);
459 macFont.setName(name);
460 }
461
462 if (!_fontRegistry.contains(macFont.getName()))
463 generateFontSubstitute(macFont);
464 }
465
466 font = FontMan.getFontByName(macFont.getName());
467
468 if (!font) {
469 debug(1, "Cannot load font '%s'", macFont.getName().c_str());
470
471 font = FontMan.getFontByName(MacFont(kMacFontChicago, 12).getName());
472 }
473 }
474
475 #ifdef USE_FREETYPE2
476 if (!font) {
477 if (_mode & kWMModeUnicode) {
478 if (macFont.getSize() <= 0) {
479 debug(1, "MacFontManager::getFont() - Font size <= 0!");
480 }
481 Common::HashMap<int, const Graphics::Font *>::iterator pFont = _uniFonts.find(macFont.getSize());
482
483 if (pFont != _uniFonts.end()) {
484 font = pFont->_value;
485 } else {
486 font = Graphics::loadTTFFontFromArchive("FreeSans.ttf", macFont.getSize(), Graphics::kTTFSizeModeCharacter, 0, Graphics::kTTFRenderModeMonochrome);
487 _uniFonts[macFont.getSize()] = font;
488 }
489 }
490 }
491 #endif
492
493 if (!font)
494 font = FontMan.getFontByUsage(macFont.getFallback());
495
496 return font;
497 }
498
parseFontSlant(Common::String slant)499 int MacFontManager::parseFontSlant(Common::String slant) {
500 slant.toUppercase();
501 int slantVal = 0;
502
503 if (slant == "I")
504 slantVal |= kMacFontItalic;
505 if (slant == "B")
506 slantVal |= kMacFontBold;
507 if (slant == "R")
508 slantVal |= kMacFontRegular;
509
510 return slantVal;
511 }
512
parseSlantFromName(const Common::String & name)513 int MacFontManager::parseSlantFromName(const Common::String &name) {
514 int slantVal = 0;
515
516 if (name.contains(" Bold"))
517 slantVal |= kMacFontBold;
518 if (name.contains(" Italic"))
519 slantVal |= kMacFontItalic;
520 if (name.contains(" Regular"))
521 slantVal |= kMacFontRegular;
522 if (name.contains(" Underline"))
523 slantVal |= kMacFontUnderline;
524 if (name.contains(" Shadow"))
525 slantVal |= kMacFontShadow;
526 if (name.contains(" Outline"))
527 slantVal |= kMacFontOutline;
528 if (name.contains(" Condense"))
529 slantVal |= kMacFontCondense;
530 if (name.contains(" Extend"))
531 slantVal |= kMacFontExtend;
532
533 return slantVal;
534 }
535
registerFontName(Common::String name,int preferredId)536 int MacFontManager::registerFontName(Common::String name, int preferredId) {
537 // Don't register an empty font name, just return Geneva's ID.
538 if (name.empty())
539 return 1;
540
541 if (_fontIds.contains(name))
542 return _fontIds[name];
543
544 int id;
545 if (preferredId > -1 && !_fontInfo.contains(preferredId)) {
546 id = preferredId;
547 } else {
548 // Preferred ID is already registered, find an unused one.
549 id = 100;
550 while (_fontInfo.contains(id))
551 id++;
552 }
553
554 FontInfo *info = new FontInfo;
555 info->name = name;
556 if (preferredId >= 0x4000) {
557 info->lang = Common::JA_JPN;
558 info->encoding = Common::kWindows932; // default to Shift JIS
559 } else {
560 info->encoding = Common::kMacRoman;
561 }
562 _fontInfo[id] = info;
563 _fontIds[name] = id;
564 return id;
565 }
566
setName(const char * name)567 void MacFont::setName(const char *name) {
568 _name = name;
569 }
570
getFontName(uint16 id,int size,int slant,bool tryGen)571 const Common::String MacFontManager::getFontName(uint16 id, int size, int slant, bool tryGen) {
572 Common::String rawName = getFontName(id);
573 Common::String n = cleanFontName(rawName);
574 int extraSlant = parseFontSlant(rawName);
575 // let's try parse slant from name
576 if (!extraSlant)
577 extraSlant = parseSlantFromName(rawName);
578
579 if (n.empty()) {
580 warning("MacFontManager: Requested font ID %d not found. Falling back to Geneva", id);
581 n = "Geneva";
582 }
583
584 return Common::String::format("%s-%d-%d", n.c_str(), slant | extraSlant, size);
585 }
586
getFontName(MacFont & font)587 const Common::String MacFontManager::getFontName(MacFont &font) {
588 return getFontName(font.getId(), font.getSize(), font.getSlant());
589 }
590
getFontIdByName(Common::String name)591 int MacFontManager::getFontIdByName(Common::String name) {
592 if (_fontIds.contains(name))
593 return _fontIds[name];
594
595 return 1;
596 }
597
getFontLanguage(uint16 id)598 Common::Language MacFontManager::getFontLanguage(uint16 id) {
599 if (!_fontInfo.contains(id)) {
600 warning("MacFontManager::getFontLanguage: No _fontInfo entry for font %d", id);
601 return Common::UNK_LANG;
602 }
603 if (_fontInfo[id]->aliasForId > -1) {
604 return getFontLanguage(_fontInfo[id]->aliasForId);
605 }
606 return _fontInfo[id]->lang;
607 }
608
getFontEncoding(uint16 id)609 Common::CodePage MacFontManager::getFontEncoding(uint16 id) {
610 if (!_fontInfo.contains(id)) {
611 warning("MacFontManager::getFontEncoding: No _fontInfo entry for font %d", id);
612 return Common::kCodePageInvalid;
613 }
614 if (_fontInfo[id]->aliasForId > -1) {
615 return getFontEncoding(_fontInfo[id]->aliasForId);
616 }
617 return _fontInfo[id]->encoding;
618 }
619
getFontAliasForId(uint16 id)620 int MacFontManager::getFontAliasForId(uint16 id) {
621 if (!_fontInfo.contains(id)) {
622 warning("MacFontManager::getFontAliasForId: No _fontInfo entry for font %d", id);
623 return -1;
624 }
625 return _fontInfo[id]->aliasForId;
626 }
627
getFontName(uint16 id)628 Common::String MacFontManager::getFontName(uint16 id) {
629 if (!_fontInfo.contains(id)) {
630 warning("MacFontManager::getFontAliasForId: No _fontInfo entry for font %d", id);
631 return "";
632 }
633 if (_fontInfo[id]->aliasForId > -1) {
634 return getFontName(_fontInfo[id]->aliasForId);
635 }
636 return _fontInfo[id]->name;
637 }
638
generateFontSubstitute(MacFont & macFont)639 void MacFontManager::generateFontSubstitute(MacFont &macFont) {
640 Common::String name;
641
642 #ifdef USE_FREETYPE2
643 // Check if we have TTF data for this font.
644 name = getFontName(macFont.getId(), 0, macFont.getSlant());
645 if (_ttfData.contains(name)) {
646 generateTTFFont(macFont, _ttfData[name]);
647 return;
648 }
649 #endif
650
651 // Try to see if we have regular font
652 if (macFont.getSlant() != kMacFontRegular) {
653 name = getFontName(macFont.getId(), macFont.getSize(), kMacFontRegular);
654
655 if (_fontRegistry.contains(name) && !_fontRegistry[name]->isGenerated()) {
656 generateFONTFont(macFont, *_fontRegistry[name]);
657
658 return;
659 }
660 }
661
662 // Now try twice size
663 name = getFontName(macFont.getId(), macFont.getSize() * 2, macFont.getSlant());
664 if (_fontRegistry.contains(name) && !_fontRegistry[name]->isGenerated()) {
665 generateFONTFont(macFont, *_fontRegistry[name]);
666
667 return;
668 }
669
670 // Now half size
671 name = getFontName(macFont.getId(), macFont.getSize() / 2, macFont.getSlant());
672 if (_fontRegistry.contains(name) && !_fontRegistry[name]->isGenerated()) {
673 generateFONTFont(macFont, *_fontRegistry[name]);
674
675 return;
676 }
677
678 // No simple substitute was found. Looking for neighborhood fonts
679
680 // First we gather all font sizes for this font
681 Common::Array<MacFont *> sizes;
682 for (Common::HashMap<Common::String, MacFont *>::iterator i = _fontRegistry.begin(); i != _fontRegistry.end(); ++i) {
683 if (i->_value->getId() == macFont.getId() && i->_value->getSlant() == macFont.getSlant() && !i->_value->isGenerated())
684 sizes.push_back(i->_value);
685 }
686
687 if (sizes.empty()) {
688 if (macFont.getSlant() == kMacFontRegular) {
689 debug(1, "No viable substitute found (1) for font %s", getFontName(macFont).c_str());
690 return;
691 }
692
693 // Now let's try to find a regular font
694 for (Common::HashMap<Common::String, MacFont *>::iterator i = _fontRegistry.begin(); i != _fontRegistry.end(); ++i) {
695 if (i->_value->getId() == macFont.getId() && i->_value->getSlant() == kMacFontRegular && !i->_value->isGenerated())
696 sizes.push_back(i->_value);
697 }
698
699 if (sizes.empty()) {
700 debug(1, "No viable substitute found (2) for font %s", getFontName(macFont).c_str());
701 return;
702 }
703 }
704
705 // Now looking for the next larger font, and store the largest one for next check
706 MacFont *candidate = nullptr;
707 MacFont *maxSize = sizes[0];
708 for (uint i = 0; i < sizes.size(); i++) {
709 if (sizes[i]->getSize() == macFont.getSize()) { // Same size but regular slant
710 candidate = sizes[i];
711 break;
712 }
713
714 if ((!candidate && sizes[i]->getSize() > macFont.getSize())
715 || (candidate && sizes[i]->getSize() < candidate->getSize()))
716 candidate = sizes[i];
717
718 if (sizes[i]->getSize() > maxSize->getSize())
719 maxSize = sizes[i];
720 }
721
722 if (candidate) {
723 generateFONTFont(macFont, *candidate);
724 return;
725 }
726
727 // Now next smaller font, which is the biggest we have
728 generateFONTFont(macFont, *maxSize);
729 }
730
731 #ifdef USE_FREETYPE2
generateTTFFont(MacFont & toFont,Common::SeekableReadStream * stream)732 void MacFontManager::generateTTFFont(MacFont &toFont, Common::SeekableReadStream *stream) {
733 debug("Generating TTF font '%s'", getFontName(toFont).c_str());
734
735 // TODO: Handle getSlant() flags
736
737 stream->seek(0);
738 Font *font = Graphics::loadTTFFont(*stream, toFont.getSize());
739
740 if (!font) {
741 warning("Failed to generate font '%s'", getFontName(toFont).c_str());
742 }
743
744 toFont.setGenerated(true);
745 toFont.setFont(font, true);
746
747 FontMan.assignFontToName(getFontName(toFont), font);
748 _fontRegistry.setVal(getFontName(toFont), new MacFont(toFont));
749
750 debug("Generated font '%s'", getFontName(toFont).c_str());
751 }
752 #endif
753
generateFONTFont(MacFont & toFont,MacFont & fromFont)754 void MacFontManager::generateFONTFont(MacFont &toFont, MacFont &fromFont) {
755 if (fromFont.isTrueType()) {
756 warning("Cannot generate FONT font '%s' from TTF font '%s'", getFontName(toFont).c_str(), getFontName(fromFont).c_str());
757 return;
758 }
759
760 debugN("Found font substitute for font '%s' ", getFontName(toFont).c_str());
761 debug("as '%s'", getFontName(fromFont).c_str());
762
763 int slant = kMacFontRegular;
764 if (fromFont.getSlant() == kMacFontRegular)
765 slant = toFont.getSlant();
766
767 MacFONTFont *fromFONTFont = static_cast<MacFONTFont *>(fromFont.getFont());
768 MacFONTFont *font = Graphics::MacFONTFont::scaleFont(fromFONTFont, toFont.getSize(), slant);
769
770 if (!font) {
771 warning("Failed to generate font '%s'", getFontName(toFont).c_str());
772 }
773
774 toFont.setGenerated(true);
775 toFont.setFont(font, false);
776
777 FontMan.assignFontToName(getFontName(toFont), font);
778 _fontRegistry.setVal(getFontName(toFont), new MacFont(toFont));
779
780 debug("Generated font '%s'", getFontName(toFont).c_str());
781 }
782
783 } // End of namespace Graphics
784