Antkeeper  0.0.1
ft-typeface.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 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 
21 #include <stdexcept>
22 #include <string>
23 
24 namespace type {
25 
26 ft_typeface::ft_typeface(FT_Library library, FT_Face face, std::unique_ptr<std::vector<FT_Byte>> file_buffer):
27  library(library),
28  face(face),
29  file_buffer{std::move(file_buffer)},
30  height(-1.0f)
31 {
33  FT_UInt index;
34  FT_ULong c = FT_Get_First_Char(face, &index);
35  while (index)
36  {
37  this->charset.insert(static_cast<char32_t>(c));
38  c = FT_Get_Next_Char(face, c, &index);
39  }
40 }
41 
43 {
44  FT_Done_Face(face);
45  FT_Done_FreeType(library);
46 }
47 
49 {
50  return FT_HAS_KERNING(face);
51 }
52 
53 bool ft_typeface::get_metrics(float height, font_metrics& metrics) const
54 {
55  // Set font size
56  set_face_pixel_size(height);
57 
58  // Get font metrics
59  metrics.size = height;
60  metrics.ascent = face->size->metrics.ascender / 64.0f;
61  metrics.descent = face->size->metrics.descender / 64.0f;
62  metrics.linespace = face->size->metrics.height / 64.0f;
63  metrics.linegap = metrics.linespace - (metrics.ascent - metrics.descent);
64  metrics.underline_position = FT_MulFix(face->underline_position, face->size->metrics.y_scale) / 64.0f;
65  metrics.underline_thickness = FT_MulFix(face->underline_thickness, face->size->metrics.y_scale) / 64.0f;
66  metrics.max_horizontal_advance = face->size->metrics.max_advance / 64.0f;
67  metrics.max_vertical_advance = FT_MulFix(face->max_advance_height, face->size->metrics.y_scale) / 64.0f;
68 
69  return true;
70 }
71 
72 bool ft_typeface::get_metrics(float height, char32_t code, glyph_metrics& metrics) const
73 {
74  // Set font size
75  set_face_pixel_size(height);
76 
77  // Get index of glyph
78  FT_UInt glyph_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(code));
79 
80  // Load glyph and render bitmap
81  if (FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT))
82  {
83  throw std::runtime_error("FreeType failed to load glyph (error code " + std::to_string(error) + ")");
84  }
85 
86  // Get glyph metrics
87  metrics.width = face->glyph->metrics.width / 64.0f;
88  metrics.height = face->glyph->metrics.height / 64.0f;
89  metrics.horizontal_bearing.x() = face->glyph->metrics.horiBearingX / 64.0f;
90  metrics.horizontal_bearing.y() = face->glyph->metrics.horiBearingY / 64.0f;
91  metrics.vertical_bearing.x() = face->glyph->metrics.vertBearingX / 64.0f;
92  metrics.vertical_bearing.y() = face->glyph->metrics.vertBearingY / 64.0f;
93  metrics.horizontal_advance = face->glyph->metrics.horiAdvance / 64.0f;
94  metrics.vertical_advance = face->glyph->metrics.vertAdvance / 64.0f;
95 
96  return true;
97 }
98 
99 bool ft_typeface::get_bitmap(float height, char32_t code, std::vector<std::byte>& bitmap, std::uint32_t& bitmap_width, std::uint32_t& bitmap_height) const
100 {
101  // Set font size
102  set_face_pixel_size(height);
103 
104  // Get index of glyph
105  FT_UInt glyph_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(code));
106 
107  // Load glyph and render bitmap
108  if (FT_Error error = FT_Load_Glyph(face, glyph_index, FT_LOAD_RENDER | FT_LOAD_TARGET_(FT_RENDER_MODE_NORMAL)))
109  {
110  throw std::runtime_error("FreeType failed to load glyph (error code " + std::to_string(error) + ")");
111  }
112 
113  // Copy glyph bitmap data into bitmap
114  bitmap.resize(face->glyph->bitmap.width * face->glyph->bitmap.rows);
115  std::memcpy(bitmap.data(), face->glyph->bitmap.buffer, bitmap.size());
116 
117  bitmap_width = static_cast<std::uint32_t>(face->glyph->bitmap.width);
118  bitmap_height = static_cast<std::uint32_t>(face->glyph->bitmap.rows);
119 
120  return true;
121 }
122 
123 bool ft_typeface::get_kerning(float height, char32_t first, char32_t second, math::fvec2& offset) const
124 {
125  // Check if typeface has kerning information
126  if (!has_kerning())
127  {
128  return false;
129  }
130 
131  // Set font size
132  set_face_pixel_size(height);
133 
134  // Get indices of the two glyphs
135  const FT_UInt first_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(first));
136  const FT_UInt second_index = FT_Get_Char_Index(face, static_cast<FT_ULong>(second));
137 
138  // Get kerning vector
139  FT_Vector kerning;
140  if (FT_Error error = FT_Get_Kerning(face, first_index, second_index, FT_KERNING_DEFAULT, &kerning))
141  {
142  throw std::runtime_error("FreeType failed to get kerning vector (error code " + std::to_string(error) + ")");
143  }
144 
145  offset = math::fvec2{static_cast<float>(kerning.x), static_cast<float>(kerning.y)} / 64.0f;
146 
147  return true;
148 }
149 
150 void ft_typeface::set_face_pixel_size(float height) const
151 {
152  if (this->height == height)
153  {
154  return;
155  }
156 
157  if (FT_Error error = FT_Set_Pixel_Sizes(face, 0, static_cast<FT_UInt>(height)))
158  {
159  throw std::runtime_error("FreeType failed to set face size (error code " + std::to_string(error) + ")");
160  }
161 
162  this->height = height;
163 }
164 
165 } // namespace type
virtual ~ft_typeface()
Destroys a FreeType typeface.
Definition: ft-typeface.cpp:42
ft_typeface(FT_Library library, FT_Face face, std::unique_ptr< std::vector< FT_Byte >> file_buffer)
Creates a FreeType typeface.
Definition: ft-typeface.cpp:26
virtual bool get_metrics(float height, font_metrics &metrics) const
Gets metrics for a font of the specified size.
Definition: ft-typeface.cpp:53
virtual bool get_kerning(float height, char32_t first, char32_t second, math::fvec2 &offset) const
Gets the kerning offset for a pair of glyphs.
virtual bool has_kerning() const
Returns true if the typeface contains kerning information, false otherwise.
Definition: ft-typeface.cpp:48
virtual bool get_bitmap(float height, char32_t code, std::vector< std::byte > &bitmap, std::uint32_t &bitmap_width, std::uint32_t &bitmap_height) const
Gets a bitmap of a glyph in a font of the specified size.
Definition: ft-typeface.cpp:99
std::unordered_set< char32_t > charset
Definition: typeface.hpp:142
T offset(T longitude)
Calculates the UTC offset at a given longitude.
Definition: utc.hpp:38
Text and typography.
Definition: bitmap-font.cpp:24
n-dimensional vector.
Definition: vector.hpp:44
constexpr element_type & x() noexcept
Returns a reference to the first element.
Definition: vector.hpp:164
constexpr element_type & y() noexcept
Returns a reference to the second element.
Definition: vector.hpp:180
Metrics describing properties of a font.
float max_vertical_advance
Maximum advance height for all glyphs, for vertical layouts.
float underline_position
Vertical position of an underline.
float linespace
Baseline-to-baseline distance, computed as ascent - descent + linegap.
float linegap
Distance that must be placed between two lines of text.
float underline_thickness
Thickness of an underline.
float descent
Negative distance from the baseline to the lowest grid coordinate.
float size
Vertical size of the font.
float ascent
Positive distance from the baseline to the highest or upper grid coordinate.
float max_horizontal_advance
Maximum advance with for all glyphs, for horizontal layouts.
Metrics describing properties of a glyph.
float height
Vertical extent of the glyph.
float vertical_advance
Distance to move the pen position after the glyph has been rendered, in vertical layouts.
math::fvec2 vertical_bearing
Offset from the pen position to the glph's top-left edge, in vertical layouts.
float width
Horizontal extent of the glyph.
math::fvec2 horizontal_bearing
Offset from the pen position to the glyph's top-left edge, in horizontal layouts.
float horizontal_advance
Distance to move the pen position after the glyph has been rendered, in horizontal layouts.