FontChain.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * FontChain.cpp, part of VCMI engine
  3. *
  4. * Authors: listed in file AUTHORS in main folder
  5. *
  6. * License: GNU General Public License v2.0 or later
  7. * Full text of license available in license.txt file, in main folder
  8. *
  9. */
  10. #include "StdInc.h"
  11. #include "FontChain.h"
  12. #include "CTrueTypeFont.h"
  13. #include "CBitmapFont.h"
  14. #include "../../lib/CConfigHandler.h"
  15. #include "../../lib/texts/TextOperations.h"
  16. void FontChain::renderText(SDL_Surface * surface, const std::string & data, const ColorRGBA & color, const Point & pos) const
  17. {
  18. auto chunks = splitTextToChunks(data);
  19. int maxAscent = getFontAscentScaled();
  20. Point currentPos = pos;
  21. for (auto const & chunk : chunks)
  22. {
  23. Point chunkPos = currentPos;
  24. int currAscent = chunk.font->getFontAscentScaled();
  25. chunkPos.y += maxAscent - currAscent;
  26. chunk.font->renderText(surface, chunk.text, color, chunkPos);
  27. currentPos.x += chunk.font->getStringWidthScaled(chunk.text);
  28. }
  29. }
  30. size_t FontChain::getFontAscentScaled() const
  31. {
  32. size_t maxHeight = 0;
  33. for(const auto & font : chain)
  34. maxHeight = std::max(maxHeight, font->getFontAscentScaled());
  35. return maxHeight;
  36. }
  37. bool FontChain::bitmapFontsPrioritized() const
  38. {
  39. const std::string & fontType = settings["video"]["fontsType"].String();
  40. if (fontType == "original")
  41. return true;
  42. if (fontType == "scalable")
  43. return false;
  44. // else - autoselection.
  45. if (getScalingFactor() != 1)
  46. return false; // If xbrz in use ttf/scalable fonts are preferred
  47. if (!vstd::isAlmostEqual(1.0, settings["video"]["fontScalingFactor"].Float()))
  48. return false; // If player requested non-100% scaling - use scalable fonts
  49. return true; // else - use original bitmap fonts
  50. }
  51. void FontChain::addTrueTypeFont(const JsonNode & trueTypeConfig)
  52. {
  53. chain.insert(chain.begin(), std::make_unique<CTrueTypeFont>(trueTypeConfig));
  54. }
  55. void FontChain::addBitmapFont(const std::string & bitmapFilename)
  56. {
  57. if (bitmapFontsPrioritized())
  58. chain.insert(chain.begin(), std::make_unique<CBitmapFont>(bitmapFilename));
  59. else
  60. chain.push_back(std::make_unique<CBitmapFont>(bitmapFilename));
  61. }
  62. bool FontChain::canRepresentCharacter(const char * data) const
  63. {
  64. for(const auto & font : chain)
  65. if (font->canRepresentCharacter(data))
  66. return true;
  67. return false;
  68. }
  69. size_t FontChain::getLineHeightScaled() const
  70. {
  71. size_t maxHeight = 0;
  72. for(const auto & font : chain)
  73. maxHeight = std::max(maxHeight, font->getLineHeightScaled());
  74. return maxHeight;
  75. }
  76. size_t FontChain::getGlyphWidthScaled(const char * data) const
  77. {
  78. for(const auto & font : chain)
  79. if (font->canRepresentCharacter(data))
  80. return font->getGlyphWidthScaled(data);
  81. return 0;
  82. }
  83. std::vector<FontChain::TextChunk> FontChain::splitTextToChunks(const std::string & data) const
  84. {
  85. std::vector<TextChunk> chunks;
  86. for (size_t i = 0; i < data.size(); i += TextOperations::getUnicodeCharacterSize(data[i]))
  87. {
  88. const IFont * currentFont = nullptr;
  89. for(const auto & font : chain)
  90. {
  91. if (font->canRepresentCharacter(data.data() + i))
  92. {
  93. currentFont = font.get();
  94. break;
  95. }
  96. }
  97. if (currentFont == nullptr)
  98. continue; // not representable
  99. std::string symbol = data.substr(i, TextOperations::getUnicodeCharacterSize(data[i]));
  100. if (chunks.empty() || chunks.back().font != currentFont)
  101. chunks.push_back({currentFont, symbol});
  102. else
  103. chunks.back().text += symbol;
  104. }
  105. return chunks;
  106. }
  107. size_t FontChain::getStringWidthScaled(const std::string & data) const
  108. {
  109. size_t result = 0;
  110. auto chunks = splitTextToChunks(data);
  111. for (auto const & chunk : chunks)
  112. result += chunk.font->getStringWidthScaled(chunk.text);
  113. return result;
  114. }