llfontregistry.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. /**
  2. * @file llfontregistry.cpp
  3. * @author Brad Payne
  4. * @brief Storage for fonts.
  5. *
  6. * $LicenseInfo:firstyear=2008&license=viewergpl$
  7. *
  8. * Copyright (c) 2008-2009, Linden Research, Inc.
  9. *
  10. * Second Life Viewer Source Code
  11. * The source code in this file ("Source Code") is provided by Linden Lab
  12. * to you under the terms of the GNU General Public License, version 2.0
  13. * ("GPL"), unless you have obtained a separate licensing agreement
  14. * ("Other License"), formally executed by you and Linden Lab. Terms of
  15. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  16. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  17. *
  18. * There are special exceptions to the terms and conditions of the GPL as
  19. * it is applied to this Source Code. View the full text of the exception
  20. * in the file doc/FLOSS-exception.txt in this software distribution, or
  21. * online at
  22. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  23. *
  24. * By copying, modifying or distributing this software, you acknowledge
  25. * that you have read and understood your obligations described above,
  26. * and agree to abide by those obligations.
  27. *
  28. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  29. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  30. * COMPLETENESS OR PERFORMANCE.
  31. * $/LicenseInfo$
  32. */
  33. #include "linden_common.h"
  34. #include <algorithm>
  35. #include "boost/tokenizer.hpp"
  36. #include "llfontregistry.h"
  37. #include "lldir.h"
  38. #include "llfontfreetype.h"
  39. #include "llfontgl.h"
  40. #include "llgl.h"
  41. #include "llwindow.h"
  42. #include "llxmlnode.h"
  43. #define NORM_DESC 1
  44. #if LL_WINDOWS
  45. # define CURRENT_OS_NAME "Windows"
  46. #elif LL_DARWIN
  47. # define CURRENT_OS_NAME "Mac"
  48. #elif LL_LINUX
  49. # define CURRENT_OS_NAME "Linux"
  50. #else
  51. # define CURRENT_OS_NAME ""
  52. #endif
  53. static const std::string s_template_string("TEMPLATE");
  54. // Helper functions
  55. static bool font_desc_init_from_xml(LLXMLNodePtr node, LLFontDescriptor& desc)
  56. {
  57. if (node->hasName("font"))
  58. {
  59. std::string attr_name;
  60. if (node->getAttributeString("name", attr_name))
  61. {
  62. #if LL_WINDOWS
  63. // File names are case-insensitive under Windows... HB
  64. LLStringUtil::toLower(attr_name);
  65. #endif
  66. desc.setName(attr_name);
  67. }
  68. std::string attr_style;
  69. if (node->getAttributeString("font_style", attr_style))
  70. {
  71. desc.setStyle(LLFontGL::getStyleFromString(attr_style));
  72. }
  73. desc.setSize(s_template_string);
  74. }
  75. LLXMLNodePtr child;
  76. for (child = node->getFirstChild(); child.notNull();
  77. child = child->getNextSibling())
  78. {
  79. std::string child_name;
  80. child->getAttributeString("name", child_name);
  81. if (child->hasName("file"))
  82. {
  83. std::string fontname = child->getTextContents();
  84. std::string char_functor;
  85. if (child->hasAttribute("functor"))
  86. {
  87. child->getAttributeString("functor", char_functor);
  88. }
  89. #if LL_WINDOWS
  90. // File names are case-insensitive under Windows... HB
  91. LLStringUtil::toLower(fontname);
  92. #endif
  93. desc.addFontFile(fontname, char_functor);
  94. }
  95. else if (child->hasName("os"))
  96. {
  97. if (child_name == CURRENT_OS_NAME)
  98. {
  99. font_desc_init_from_xml(child, desc);
  100. }
  101. }
  102. }
  103. return true;
  104. }
  105. bool init_from_xml(LLFontRegistry* registry, LLXMLNodePtr node)
  106. {
  107. LLXMLNodePtr child;
  108. for (child = node->getFirstChild(); child.notNull();
  109. child = child->getNextSibling())
  110. {
  111. std::string child_name;
  112. child->getAttributeString("name", child_name);
  113. if (child->hasName("font"))
  114. {
  115. LLFontDescriptor desc;
  116. bool font_succ = font_desc_init_from_xml(child, desc);
  117. LLFontDescriptor norm_desc = desc.normalize();
  118. if (font_succ)
  119. {
  120. // If this is the first time we have seen this font name,
  121. // create a new template map entry for it.
  122. const LLFontDescriptor* match_desc =
  123. registry->getMatchingFontDesc(desc);
  124. if (!match_desc)
  125. {
  126. // Create a new entry (with no corresponding font).
  127. registry->mFontMap[norm_desc] = NULL;
  128. }
  129. // Otherwise, find the existing entry and combine data.
  130. else
  131. {
  132. // Prepend files from desc. A little roundabout because the
  133. // map key is const, so we have to fetch it, make a new map
  134. // key and replace the old entry.
  135. font_file_info_vec_t font_files =
  136. match_desc->getFontFiles();
  137. font_files.insert(font_files.begin(),
  138. desc.getFontFiles().begin(),
  139. desc.getFontFiles().end());
  140. LLFontDescriptor new_desc = *match_desc;
  141. new_desc.setFontFiles(font_files);
  142. registry->mFontMap.erase(*match_desc);
  143. registry->mFontMap[new_desc] = NULL;
  144. }
  145. }
  146. }
  147. else if (child->hasName("font_size"))
  148. {
  149. std::string size_name;
  150. F32 size_value;
  151. if (child->getAttributeString("name", size_name) &&
  152. child->getAttributeF32("size", size_value))
  153. {
  154. registry->mFontSizes[size_name] = size_value;
  155. }
  156. }
  157. }
  158. return true;
  159. }
  160. ///////////////////////////////////////////////////////////////////////////////
  161. // LLFontDescriptor class
  162. ///////////////////////////////////////////////////////////////////////////////
  163. //static
  164. LLFontDescriptor::char_functor_map_t
  165. LLFontDescriptor::sCharFunctors({ { "is_emoji", LLStringOps::isEmoji } });
  166. LLFontDescriptor::LLFontDescriptor()
  167. : mStyle(0)
  168. {
  169. }
  170. LLFontDescriptor::LLFontDescriptor(const std::string& name,
  171. const std::string& size, U8 style,
  172. const font_file_info_vec_t& font_files)
  173. : mName(name),
  174. mSize(size),
  175. mStyle(style),
  176. mFontFiles(font_files)
  177. {
  178. #if LL_WINDOWS
  179. // File names are case-insensitive under Windows... HB
  180. LLStringUtil::toLower(mName);
  181. #endif
  182. }
  183. LLFontDescriptor::LLFontDescriptor(const std::string& name,
  184. const std::string& size, U8 style)
  185. : mName(name),
  186. mSize(size),
  187. mStyle(style)
  188. {
  189. #if LL_WINDOWS
  190. // File names are case-insensitive under Windows... HB
  191. LLStringUtil::toLower(mName);
  192. #endif
  193. }
  194. bool LLFontDescriptor::operator<(const LLFontDescriptor& b) const
  195. {
  196. if (mName == b.mName)
  197. {
  198. if (mStyle == b.mStyle)
  199. {
  200. return mSize < b.mSize;
  201. }
  202. return mStyle < b.mStyle;
  203. }
  204. return mName < b.mName;
  205. }
  206. bool LLFontDescriptor::isTemplate() const
  207. {
  208. return getSize() == s_template_string;
  209. }
  210. // Look for substring match and remove substring if matched.
  211. bool removeSubString(std::string& str, const std::string& substr)
  212. {
  213. size_t pos = str.find(substr);
  214. if (pos == std::string::npos)
  215. {
  216. return false;
  217. }
  218. str.erase(pos, substr.size());
  219. return true;
  220. }
  221. // Normal form is
  222. // - raw name
  223. // - bold, italic style info reflected in both style and font name.
  224. // - other style info removed.
  225. // - size info moved to mSize, defaults to Medium
  226. // For example,
  227. // - "SansSerifHuge" would normalize to { "SansSerif", "Huge", 0 }
  228. // - "SansSerifBold" would normalize to { "SansSerifBold", "Medium", BOLD }
  229. LLFontDescriptor LLFontDescriptor::normalize() const
  230. {
  231. #if LL_WINDOWS
  232. // File names are case-insensitive under Windows... HB
  233. static const std::string tiny_str("tiny");
  234. static const std::string little_str("little");
  235. static const std::string small_str("small");
  236. static const std::string medium_str("medium");
  237. static const std::string large_str("large");
  238. static const std::string big_str("big");
  239. static const std::string huge_str("huge");
  240. static const std::string monospace_str("monospace");
  241. static const std::string bold_str("bold");
  242. static const std::string italic_str("italic");
  243. #else
  244. static const std::string tiny_str("Tiny");
  245. static const std::string little_str("Little");
  246. static const std::string small_str("Small");
  247. static const std::string medium_str("Medium");
  248. static const std::string large_str("Large");
  249. static const std::string big_str("Big");
  250. static const std::string huge_str("Huge");
  251. static const std::string monospace_str("Monospace");
  252. static const std::string bold_str("Bold");
  253. static const std::string italic_str("Italic");
  254. #endif
  255. std::string new_name(mName);
  256. #if LL_WINDOWS
  257. // File names are case-insensitive under Windows... HB
  258. LLStringUtil::toLower(new_name);
  259. #endif
  260. std::string new_size(mSize);
  261. U8 new_style(mStyle);
  262. // Only care about style to extent it can be picked up by font.
  263. new_style &= LLFontGL::BOLD | LLFontGL::ITALIC;
  264. // All these transformations are to support old-style font specifications.
  265. if (removeSubString(new_name, tiny_str))
  266. {
  267. new_size = "Tiny";
  268. }
  269. if (removeSubString(new_name, little_str))
  270. {
  271. new_size = "Little";
  272. }
  273. if (removeSubString(new_name, small_str))
  274. {
  275. new_size = "Small";
  276. }
  277. if (removeSubString(new_name, medium_str))
  278. {
  279. new_size = "Medium";
  280. }
  281. if (removeSubString(new_name, large_str) ||
  282. removeSubString(new_name, big_str))
  283. {
  284. new_size = "Large";
  285. }
  286. if (removeSubString(new_name, huge_str))
  287. {
  288. new_size = "Huge";
  289. }
  290. // *HACK: Monospace is the only one we do not remove, so name "Monospace"
  291. // does not get taken down to "". For other fonts, there is no ambiguity
  292. // between font name and size specifier.
  293. if (new_size != s_template_string && new_size.empty() &&
  294. new_name.find(monospace_str) != std::string::npos)
  295. {
  296. new_size = "Monospace";
  297. }
  298. if (new_size.empty())
  299. {
  300. new_size = "Medium";
  301. }
  302. if (removeSubString(new_name, bold_str))
  303. {
  304. new_style |= LLFontGL::BOLD;
  305. }
  306. if (removeSubString(new_name, italic_str))
  307. {
  308. new_style |= LLFontGL::ITALIC;
  309. }
  310. return LLFontDescriptor(new_name, new_size, new_style, mFontFiles);
  311. }
  312. void LLFontDescriptor::addFontFile(const std::string& file_name,
  313. const std::string& char_functor)
  314. {
  315. char_functor_map_t::const_iterator it = sCharFunctors.find(char_functor);
  316. mFontFiles.push_back(LLFontFileInfo(file_name,
  317. it != sCharFunctors.end() ? it->second : NULL));
  318. }
  319. ///////////////////////////////////////////////////////////////////////////////
  320. // LLFontRegistry class
  321. ///////////////////////////////////////////////////////////////////////////////
  322. LLFontRegistry::LLFontRegistry(const string_vec_t& xui_paths,
  323. bool create_gl_textures)
  324. : mCreateGLTextures(create_gl_textures)
  325. {
  326. // Propagate this down from LLUICtrlFactory so LLRender does not need an
  327. // upstream dependency on LLUI.
  328. mXUIPaths = xui_paths;
  329. // This is potentially a slow directory traversal, so we want to cache the
  330. // result.
  331. mUltimateFallbackList = LLWindow::getDynamicFallbackFontList();
  332. }
  333. LLFontRegistry::~LLFontRegistry()
  334. {
  335. clear();
  336. }
  337. bool LLFontRegistry::parseFontInfo(const std::string& xml_filename)
  338. {
  339. bool success = false; // Succeed if we find at least one XUI file
  340. LLXMLNodePtr root;
  341. std::string full_filename, root_name;
  342. for (S32 i = 0, count = mXUIPaths.size(); i < count; ++i)
  343. {
  344. full_filename = gDirUtil.findSkinnedFilename(mXUIPaths[i],
  345. xml_filename);
  346. if (!LLXMLNode::parseFile(full_filename, root, NULL))
  347. {
  348. continue;
  349. }
  350. if (root.isNull() || !root->hasName("fonts"))
  351. {
  352. llwarns << "Bad font info file: " << full_filename << llendl;
  353. continue;
  354. }
  355. root->getAttributeString("name", root_name);
  356. if (root->hasName("fonts"))
  357. {
  358. // Expect a collection of children consisting of "font" or
  359. // "font_size" entries
  360. success |= init_from_xml(this, root);
  361. }
  362. }
  363. if (success)
  364. {
  365. dump();
  366. }
  367. return success;
  368. }
  369. bool LLFontRegistry::nameToSize(const std::string& size_name, F32& size)
  370. {
  371. font_size_map_t::iterator it = mFontSizes.find(size_name);
  372. if (it != mFontSizes.end())
  373. {
  374. size = it->second;
  375. return true;
  376. }
  377. return false;
  378. }
  379. LLFontGL* LLFontRegistry::createFont(const LLFontDescriptor& desc)
  380. {
  381. // Name should hold a font name recognized as a setting; the value of the
  382. // setting should be a list of font files. Size should be a recognized
  383. // string value. Style should be a set of flags including any implied by
  384. // the font name.
  385. // First decipher the requested size.
  386. LLFontDescriptor norm_desc = desc.normalize();
  387. F32 point_size;
  388. bool found_size = nameToSize(norm_desc.getSize(), point_size);
  389. if (!found_size)
  390. {
  391. llwarns << "Unrecognized size " << norm_desc.getSize() << llendl;
  392. return NULL;
  393. }
  394. llinfos << norm_desc.getName() << " size " << norm_desc.getSize()
  395. << " style " << (S32)norm_desc.getStyle() << llendl;
  396. // Find corresponding font template (based on same descriptor with no size
  397. // specified)
  398. LLFontDescriptor template_desc(norm_desc);
  399. template_desc.setSize(s_template_string);
  400. const LLFontDescriptor* match_desc = getClosestFontTemplate(template_desc);
  401. if (match_desc)
  402. {
  403. // See whether this best-match font has already been instantiated in
  404. // the requested size.
  405. LLFontDescriptor nearest_exact_desc = *match_desc;
  406. nearest_exact_desc.setSize(norm_desc.getSize());
  407. font_reg_map_t::iterator it = mFontMap.find(nearest_exact_desc);
  408. if (it != mFontMap.end() && it->second != NULL)
  409. {
  410. llinfos << "Matching font exists: " << nearest_exact_desc.getName()
  411. << " - size: " << nearest_exact_desc.getSize()
  412. << " - style: " << (S32)nearest_exact_desc.getStyle()
  413. << llendl;
  414. // Copying underlying Freetype font, and storing in LLFontGL with
  415. // requested font descriptor
  416. LLFontGL* fontp = new LLFontGL;
  417. fontp->mFontDescriptor = desc;
  418. fontp->mFontFreetype = it->second->mFontFreetype;
  419. mFontMap[desc] = fontp;
  420. return fontp;
  421. }
  422. }
  423. else
  424. {
  425. // No template found in our custom fonts.xml file, which does not mean
  426. // we cannot find a matching font file name on the system, so do not
  427. // bail out just yet at this point ! HB
  428. llinfos << "No template font found in fonts.xml for "
  429. << norm_desc.getName() << " - style = "
  430. << (S32)norm_desc.getStyle() << llendl;
  431. }
  432. // Build list of font names to look for.
  433. font_file_info_vec_t font_files;
  434. if (match_desc)
  435. {
  436. // Files specified for this font come first.
  437. font_files = match_desc->getFontFiles();
  438. // Add the default font as a fallback.
  439. LLFontDescriptor default_desc("default", s_template_string);
  440. const LLFontDescriptor* match_default_desc =
  441. getMatchingFontDesc(default_desc);
  442. if (match_default_desc)
  443. {
  444. font_files.insert(font_files.end(),
  445. match_default_desc->getFontFiles().begin(),
  446. match_default_desc->getFontFiles().end());
  447. }
  448. // Add ultimate fallback list, generated dynamically on Linux, null
  449. // elsewhere.
  450. std::transform(mUltimateFallbackList.begin(),
  451. mUltimateFallbackList.end(),
  452. std::back_inserter(font_files),
  453. [](const std::string& file_name)
  454. {
  455. return LLFontFileInfo(file_name);
  456. });
  457. }
  458. else
  459. {
  460. // Try to find a matching True Type font file name on the system. HB
  461. const std::string& fname = desc.getName();
  462. font_files.emplace_back(fname + ".ttf");
  463. font_files.emplace_back(fname + ".otf");
  464. font_files.emplace_back(fname + ".ttc");
  465. font_files.emplace_back(fname + ".otc");
  466. #if !LL_WINDOWS
  467. // Linux and macOS file systems are case-sensitive...
  468. font_files.emplace_back(fname + ".TTF");
  469. font_files.emplace_back(fname + ".OTF");
  470. font_files.emplace_back(fname + ".TTC");
  471. font_files.emplace_back(fname + ".OTC");
  472. #endif
  473. const std::string& nfname = norm_desc.getName();
  474. if (nfname != fname)
  475. {
  476. font_files.emplace_back(nfname + ".ttf");
  477. font_files.emplace_back(nfname + ".otf");
  478. font_files.emplace_back(nfname + ".ttc");
  479. font_files.emplace_back(nfname + ".otc");
  480. #if !LL_WINDOWS
  481. // Linux and macOS file systems are case-sensitive...
  482. font_files.emplace_back(nfname + ".TTF");
  483. font_files.emplace_back(nfname + ".OTF");
  484. font_files.emplace_back(nfname + ".TTC");
  485. font_files.emplace_back(nfname + ".OTC");
  486. #endif
  487. }
  488. }
  489. // Load fonts based on names.
  490. if (font_files.empty())
  491. {
  492. llwarns << "Failure: no file name specified." << llendl;
  493. return NULL;
  494. }
  495. LLFontGL* resultp = NULL;
  496. // The first font will get pulled will be the "head" font, set to non-
  497. //fallback and become the "head" font, set to non-fallback. The rest will
  498. // constitute the fallback list.
  499. bool is_first_found = true;
  500. // Directories to search for fonts
  501. std::vector<std::string> font_paths;
  502. // First, our viewer installation path
  503. font_paths.emplace_back(gDirUtil.getAppRODataDir() + "/fonts/");
  504. // Then OS-specific pathes
  505. #if LL_DARWIN
  506. font_paths.emplace_back("/System/Library/Fonts/");
  507. font_paths.emplace_back("/Library/Fonts/");
  508. font_paths.emplace_back("/Library/Fonts/Supplemental/");
  509. font_paths.emplace_back("/System/Library/Fonts/Supplemental/");
  510. #elif LL_LINUX
  511. if (match_desc)
  512. {
  513. // Under Linux, file_names already contain absolute paths of fallback
  514. // fonts, so add an empty path so we can find them...
  515. font_paths.emplace_back("");
  516. }
  517. else // Try and find a matching font file name among system fonts... HB
  518. {
  519. // Make a list of unique and valid font paths.
  520. std::set<std::string> linux_paths;
  521. for (U32 i = 0, count = mUltimateFallbackList.size(); i < count; ++i)
  522. {
  523. const std::string& path = mUltimateFallbackList[i];
  524. size_t j = path.rfind('/');
  525. if (j != std::string::npos)
  526. {
  527. linux_paths.emplace(path.substr(0, j + 1));
  528. }
  529. }
  530. // Add to the list of possible paths to scan for.
  531. for (std::set<std::string>::iterator it = linux_paths.begin(),
  532. end = linux_paths.end();
  533. it != end; ++it)
  534. {
  535. font_paths.emplace_back(*it);
  536. }
  537. }
  538. #elif LL_WINDOWS
  539. // Try to figure out where the system's font files are stored.
  540. char* system_root = getenv("SystemRoot");
  541. if (system_root)
  542. {
  543. font_paths.emplace_back(llformat("%s/fonts/", system_root));
  544. }
  545. else
  546. {
  547. llwarns << "SystemRoot not found, attempting to load fonts from default path."
  548. << llendl;
  549. font_paths.emplace_back("/WINDOWS/FONTS/");
  550. }
  551. #endif
  552. // The fontname string may contain multiple font file names separated by
  553. // semicolons. Break it apart and try loading each one, in order.
  554. std::string font_path;
  555. for (S32 i = 0, count = font_files.size(); i < count; ++i)
  556. {
  557. LLFontGL* fontp = new LLFontGL;
  558. const std::string& file_name = font_files[i].mFileName;
  559. bool is_fallback = !is_first_found || !mCreateGLTextures;
  560. bool found = false;
  561. for (S32 j = 0, npaths = font_paths.size(); j < npaths; ++j)
  562. {
  563. font_path = font_paths[j] + file_name;
  564. LL_DEBUGS("FontRegistry") << "Trying: " << font_path << LL_ENDL;
  565. found = fontp->loadFace(font_path, point_size,
  566. LLFontGL::sVertDPI, LLFontGL::sHorizDPI,
  567. is_fallback);
  568. if (found)
  569. {
  570. break;
  571. }
  572. }
  573. if (!found)
  574. {
  575. if (match_desc)
  576. {
  577. llwarns_once << "Could not load font: " << file_name << llendl;
  578. }
  579. else
  580. {
  581. LL_DEBUGS("FontRegistry") << "Could not find font: "
  582. << file_name << LL_ENDL;
  583. }
  584. delete fontp;
  585. fontp = NULL;
  586. }
  587. if (fontp)
  588. {
  589. if (is_first_found)
  590. {
  591. resultp = fontp;
  592. is_first_found = false;
  593. llinfos << "Found matching font, filename: " << font_path
  594. << llendl;
  595. }
  596. else
  597. {
  598. LL_DEBUGS("FontRegistry") << "Adding: " << font_path
  599. << LL_ENDL;
  600. resultp->mFontFreetype->addFallbackFont(fontp->mFontFreetype,
  601. font_files[i].mCharFunctor);
  602. delete fontp;
  603. fontp = NULL;
  604. }
  605. }
  606. }
  607. if (!resultp && !match_desc)
  608. {
  609. llwarns << "Failure: no matching font found for "
  610. << norm_desc.getName() << " - style = "
  611. << (S32)norm_desc.getStyle() << llendl;
  612. return NULL;
  613. }
  614. #if NORM_DESC
  615. if (match_desc)
  616. {
  617. norm_desc.setStyle(match_desc->getStyle());
  618. }
  619. if (resultp)
  620. {
  621. llinfos << "Created font " << desc.getName() << " (normalized desc: "
  622. << norm_desc.getName() << ")" << llendl;
  623. resultp->mFontDescriptor = norm_desc;
  624. }
  625. else
  626. {
  627. llwarns << "Failure to create font " << desc.getName()
  628. << ": unknown reason." << llendl;
  629. }
  630. mFontMap[norm_desc] = resultp;
  631. #else
  632. if (resultp)
  633. {
  634. llinfos << "Created font " << desc.getName() << llendl;
  635. resultp->mFontDescriptor = desc;
  636. }
  637. else
  638. {
  639. llwarns << "Failure to create font " << desc.getName()
  640. << ": unknown reason." << llendl;
  641. }
  642. mFontMap[desc] = resultp;
  643. #endif
  644. return resultp;
  645. }
  646. void LLFontRegistry::reset()
  647. {
  648. for (font_reg_map_t::iterator it = mFontMap.begin(), end = mFontMap.end();
  649. it != end; ++it)
  650. {
  651. // Reset the corresponding font but preserve the entry.
  652. if (it->second)
  653. {
  654. it->second->reset();
  655. }
  656. }
  657. }
  658. void LLFontRegistry::clear()
  659. {
  660. for (font_reg_map_t::iterator it = mFontMap.begin(), end = mFontMap.end();
  661. it != end; ++it)
  662. {
  663. LLFontGL* fontp = it->second;
  664. delete fontp;
  665. }
  666. mFontMap.clear();
  667. }
  668. void LLFontRegistry::destroyGL()
  669. {
  670. for (font_reg_map_t::iterator it = mFontMap.begin(), end = mFontMap.end();
  671. it != end; ++it)
  672. {
  673. // Reset the corresponding font but preserve the entry.
  674. if (it->second)
  675. {
  676. it->second->destroyGL();
  677. }
  678. }
  679. }
  680. LLFontGL* LLFontRegistry::getFont(const LLFontDescriptor& desc, bool normalize)
  681. {
  682. font_reg_map_t::iterator it;
  683. #if NORM_DESC
  684. if (normalize)
  685. {
  686. it = mFontMap.find(desc.normalize());
  687. }
  688. else
  689. #endif
  690. {
  691. it = mFontMap.find(desc);
  692. }
  693. if (it != mFontMap.end())
  694. {
  695. return it->second;
  696. }
  697. LLFontGL* fontp = createFont(desc);
  698. if (fontp)
  699. {
  700. // Generate glyphs for ASCII chars to avoid stalls later
  701. fontp->generateASCIIglyphs();
  702. }
  703. else
  704. {
  705. llwarns << "Failure with name = " << desc.getName()
  706. << " - style = " << ((S32) desc.getStyle())
  707. << " - size = " << desc.getSize() << llendl;
  708. }
  709. return fontp;
  710. }
  711. const LLFontDescriptor* LLFontRegistry::getMatchingFontDesc(const LLFontDescriptor& desc)
  712. {
  713. LLFontDescriptor norm_desc = desc.normalize();
  714. font_reg_map_t::iterator it = mFontMap.find(norm_desc);
  715. return it != mFontMap.end() ? &(it->first) : NULL;
  716. }
  717. static U32 bitCount(U8 c)
  718. {
  719. U32 count = 0;
  720. if (c & 1) ++count;
  721. if (c & 2) ++count;
  722. if (c & 4) ++count;
  723. if (c & 8) ++count;
  724. if (c & 16) ++count;
  725. if (c & 32) ++count;
  726. if (c & 64) ++count;
  727. if (c & 128) ++count;
  728. return count;
  729. }
  730. // Find nearest match for the requested descriptor.
  731. const LLFontDescriptor* LLFontRegistry::getClosestFontTemplate(const LLFontDescriptor& desc)
  732. {
  733. const LLFontDescriptor* exact_match_desc = getMatchingFontDesc(desc);
  734. if (exact_match_desc)
  735. {
  736. return exact_match_desc;
  737. }
  738. LLFontDescriptor norm_desc = desc.normalize();
  739. const LLFontDescriptor* best_match_desc = NULL;
  740. for (font_reg_map_t::iterator it = mFontMap.begin(), end = mFontMap.end();
  741. it != end; ++it)
  742. {
  743. const LLFontDescriptor* curr_desc = &(it->first);
  744. if (!curr_desc->isTemplate() || // Ignore if not a template.
  745. // Ignore if font name is wrong:
  746. curr_desc->getName() != norm_desc.getName() ||
  747. // Reject font if it matches any bits we don't want:
  748. (curr_desc->getStyle() & ~norm_desc.getStyle()))
  749. {
  750. continue;
  751. }
  752. // Take if it is the first plausible candidate we have found.
  753. if (!best_match_desc)
  754. {
  755. best_match_desc = curr_desc;
  756. continue;
  757. }
  758. // Take if it matches more bits than anything before.
  759. U8 best_style_match_bits = norm_desc.getStyle() &
  760. best_match_desc->getStyle();
  761. U8 curr_style_match_bits = norm_desc.getStyle() &
  762. curr_desc->getStyle();
  763. if (bitCount(curr_style_match_bits) >
  764. bitCount(best_style_match_bits) ||
  765. // Take if Bold is requested and this descriptor matches it.
  766. (curr_style_match_bits & LLFontGL::BOLD))
  767. {
  768. best_match_desc = curr_desc;
  769. }
  770. }
  771. // Nothing matched.
  772. return best_match_desc;
  773. }
  774. void LLFontRegistry::dump()
  775. {
  776. llinfos << "LLFontRegistry dump: " << llendl;
  777. for (font_size_map_t::iterator size_it = mFontSizes.begin(),
  778. end = mFontSizes.end();
  779. size_it != end; ++size_it)
  780. {
  781. llinfos << "Size: " << size_it->first << " => " << size_it->second
  782. << llendl;
  783. }
  784. for (font_reg_map_t::iterator font_it = mFontMap.begin(),
  785. end = mFontMap.end();
  786. font_it != end; ++font_it)
  787. {
  788. const LLFontDescriptor& desc = font_it->first;
  789. llinfos << "Font: name = " << desc.getName() << " - style = "
  790. << ((S32)desc.getStyle()) << " - size = " << desc.getSize()
  791. << " - file names listed below:" << llendl;
  792. const font_file_info_vec_t& font_files = desc.getFontFiles();
  793. for (S32 i = 0, count = font_files.size(); i < count; ++i)
  794. {
  795. llinfos << " file: " << font_files[i].mFileName << llendl;
  796. }
  797. }
  798. }