💿🐜 Antkeeper source code https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

165 lines
5.1 KiB

  1. /*
  2. * Copyright (C) 2021 Christopher J. Howard
  3. *
  4. * This file is part of Antkeeper source code.
  5. *
  6. * Antkeeper source code is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Antkeeper source code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "type/freetype/typeface.hpp"
  20. #include <stdexcept>
  21. #include <string>
  22. namespace type {
  23. namespace freetype {
  24. typeface::typeface(FT_Library library, FT_Face face, unsigned char* buffer):
  25. library(library),
  26. face(face),
  27. buffer(buffer),
  28. height(-1.0f)
  29. {}
  30. typeface::~typeface()
  31. {
  32. FT_Done_Face(face);
  33. delete[] buffer;
  34. FT_Done_FreeType(library);
  35. }
  36. bool typeface::has_kerning() const
  37. {
  38. return FT_HAS_KERNING(face);
  39. }
  40. bool typeface::has_glyph(char32_t code) const
  41. {
  42. return FT_Get_Char_Index(face, static_cast<FT_ULong>(code)) != 0;
  43. }
  44. bool typeface::get_metrics(float height, font_metrics& metrics) const
  45. {
  46. // Set font size
  47. set_face_pixel_size(height);
  48. // Get font metrics
  49. metrics.size = height;
  50. metrics.ascent = face->size->metrics.ascender / 64.0f;
  51. metrics.descent = face->size->metrics.descender / 64.0f;
  52. metrics.linespace = face->size->metrics.height / 64.0f;
  53. metrics.linegap = metrics.linespace - (metrics.ascent - metrics.descent);
  54. metrics.underline_position = FT_MulFix(face->underline_position, face->size->metrics.y_scale) / 64.0f;
  55. metrics.underline_thickness = FT_MulFix(face->underline_thickness, face->size->metrics.y_scale) / 64.0f;
  56. metrics.max_horizontal_advance = face->size->metrics.max_advance / 64.0f;
  57. metrics.max_vertical_advance = FT_MulFix(face->max_advance_height, face->size->metrics.y_scale) / 64.0f;
  58. return true;
  59. }
  60. bool typeface::get_metrics(float height, char32_t code, glyph_metrics& metrics) const
  61. {
  62. // Set font size
  63. set_face_pixel_size(height);
  64. // Get index of glyph
  65. FT_UInt glyph_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(code));
  66. // Load glyph and render bitmap
  67. FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
  68. if (error)
  69. {
  70. throw std::runtime_error("FreeType failed to load glyph (error code " + std::to_string(error) + ")");
  71. }
  72. // Get glyph metrics
  73. metrics.width = face->glyph->metrics.width / 64.0f;
  74. metrics.height = face->glyph->metrics.height / 64.0f;
  75. metrics.horizontal_bearing.x = face->glyph->metrics.horiBearingX / 64.0f;
  76. metrics.horizontal_bearing.y = face->glyph->metrics.horiBearingY / 64.0f;
  77. metrics.vertical_bearing.x = face->glyph->metrics.vertBearingX / 64.0f;
  78. metrics.vertical_bearing.y = face->glyph->metrics.vertBearingY / 64.0f;
  79. metrics.horizontal_advance = face->glyph->metrics.horiAdvance / 64.0f;
  80. metrics.vertical_advance = face->glyph->metrics.vertAdvance / 64.0f;
  81. return true;
  82. }
  83. bool typeface::get_bitmap(float height, char32_t code, image& bitmap) const
  84. {
  85. // Set font size
  86. set_face_pixel_size(height);
  87. // Get index of glyph
  88. FT_UInt glyph_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(code));
  89. // Load glyph and render bitmap
  90. FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_(FT_RENDER_MODE_NORMAL));
  91. if (error)
  92. {
  93. throw std::runtime_error("FreeType failed to load glyph (error code " + std::to_string(error) + ")");
  94. }
  95. // Format and resize bitmap
  96. bitmap.resize(0, 0);
  97. bitmap.format(sizeof(unsigned char), 1);
  98. bitmap.resize(face->glyph->bitmap.width, face->glyph->bitmap.rows);
  99. // Copy glyph bitmap data in bitmap
  100. std::memcpy(bitmap.get_pixels(), face->glyph->bitmap.buffer, bitmap.get_size());
  101. return true;
  102. }
  103. bool typeface::get_kerning(float height, char32_t first, char32_t second, float2& offset) const
  104. {
  105. // Check if typeface has kerning information
  106. if (!has_kerning())
  107. return false;
  108. // Set font size
  109. set_face_pixel_size(height);
  110. // Get indices of the two glyphs
  111. FT_UInt first_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(first));
  112. FT_UInt second_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(second));
  113. // Get kerning vector
  114. FT_Vector kerning;
  115. FT_Error error = FT_Get_Kerning(face, first_index, second_index, FT_KERNING_DEFAULT, &kerning);
  116. if (error)
  117. {
  118. throw std::runtime_error("FreeType failed to get kerning vector (error code " + std::to_string(error) + ")");
  119. }
  120. offset = float2{static_cast<float>(kerning.x), static_cast<float>(kerning.y)} / 64.0f;
  121. return true;
  122. }
  123. void typeface::set_face_pixel_size(float height) const
  124. {
  125. if (this->height == height)
  126. return;
  127. FT_Error error = FT_Set_Pixel_Sizes(face, 0, static_cast<FT_UInt>(height));
  128. if (error)
  129. {
  130. throw std::runtime_error("FreeType failed to set face size (error code " + std::to_string(error) + ")");
  131. }
  132. this->height = height;
  133. }
  134. } // namespace freetype
  135. } // namespace type