1 // Copyright 2015-2017 the openage authors. See copying.md for legal info.
2 
3 #pragma once
4 
5 #include <memory>
6 #include <string>
7 #include <typeindex>
8 #include <vector>
9 
10 #include "../../util/hash.h"
11 #include "font_manager.h"
12 
13 // Forward Declarations of HarfBuzz stuff!
14 struct hb_font_t;
15 
16 namespace openage {
17 namespace renderer {
18 
19 constexpr int FREETYPE_UNIT = 64;
20 
21 using codepoint_t = unsigned int;
22 
23 /**
24  * Holds info about a single glyph.
25  */
26 class Glyph {
27 public:
28 	codepoint_t codepoint; //!< Glyph's codepoint.
29 	int x_offset;          //!< Horizontal distance from origin (current pen position) to glyph's leftmost boundary.
30 	int y_offset;          //!< Vertical distance from the baseline to glyph's topmost boundary.
31 	unsigned int width;    //!< Width of the glyph.
32 	unsigned int height;   //!< Height of the glyph.
33 	float x_advance;       //!< Advance width of the glyph.
34 	float y_advance;       //!< Advance height of the glyph.
35 };
36 
37 /**
38  * Enumeration of the possible font directions.
39  */
40 enum class font_direction {
41 	left_to_right,
42 	right_to_left,
43 	top_to_bottom,
44 	bottom_to_top
45 };
46 
47 /**
48  * Description for a font.
49  *
50  * An instance of font_description is capable of uniquely distinguishing a font.
51  */
52 struct font_description {
53 	std::string font_file;    //!< Path to the font's file.
54 	unsigned int size;        //!< Points size of the font.
55 	font_direction direction; //!< The direction of the font.
56 	std::string language;     //!< Language of the font.
57 	std::string script;       //!< The font's script.
58 
59 	/**
60 	 * Constructs a font_description instance.
61 	 *
62 	 * @param font_file: The path to fon't font.
63 	 * @param size: The size of the font in points.
64 	 * @param direction: The direction of font.
65 	 * @param language: The font's language.
66 	 * @param script: The font's script.
67 	 */
68 	font_description(const std::string &font_file,
69 	                 unsigned int size,
70 	                 font_direction direction = font_direction::left_to_right,
71 	                 const std::string &language = "en",
72 	                 const std::string &script = "Latn");
73 
74 	/**
75 	 * Constructs a font_description instance.
76 	 *
77 	 * This constructor uses fontconfig to determine a font file for the specified font family and style.
78 	 *
79 	 * @param family: The font family.
80 	 * @param style: The font style.
81 	 * @param size: The size of the font in points.
82 	 */
83 	font_description(const char *family, const char *style, unsigned int size);
84 
85 	font_description(const font_description &other);
86 
87 	font_description &operator=(const font_description &other);
88 
89 	bool operator==(const font_description &other) const;
90 
91 	bool operator!=(const font_description &other) const;
92 
93 };
94 
95 class Font {
96 
97 public:
98 	/**
99 	 * Create a font instance from the description.
100 	 *
101 	 * @param description: the font description.
102 	 */
103 	Font(const font_description &description);
104 
105 	/**
106 	 * This constructor is used by the font manager to create a
107 	 * new font instance from the description.
108 	 *
109 	 * @param font_manager: The font manager.
110 	 * @param description: the font description.
111 	 */
112 	Font(FontManager *font_manager, const font_description &description);
113 
114 	virtual ~Font();
115 
116 	/**
117 	 * Get the typographic ascender of font.
118 	 *
119 	 * @returns The ascender of font.
120 	 */
121 	float get_ascender() const;
122 
123 	/**
124 	 * Get the typographic descender of font.
125 	 *
126 	 * @returns The descender of font.
127 	 */
128 	float get_descender() const;
129 
130 	/**
131 	 * Get the line spacing of font.
132 	 *
133 	 * @returns The font's line height.
134 	 */
135 	float get_line_height() const;
136 
137 	/**
138 	 * Get the kerning adjustment between two glyphs.
139 	 *
140 	 * @param left_glyph: The first glyph.
141 	 * @param right_glyph: The next glyph.
142 	 * @returns The kerning adjustment.
143 	 */
144 	float get_horizontal_kerning(codepoint_t left_glyph, codepoint_t right_glyph) const;
145 
146 	/**
147 	 * Get the advance width of a particular string.
148 	 *
149 	 * @param text: The string for which the width is to be determined.
150 	 * @returns The advance width of the specified string.
151 	 */
152 	float get_advance_width(const std::string &text) const;
153 
154 	/**
155 	 * Get the list of glyphs for a particular string.
156 	 *
157 	 * @param text: the string for which the glyphs are to be retrieved.
158 	 * @returns The list of the glyphs.
159 	 */
160 	std::vector<codepoint_t> get_glyphs(const std::string &text) const;
161 
162 	/**
163 	 * Load a particular glyph's info and retrieves the glyph's bitmap data.
164 	 *
165 	 * @param codepoint: The glyph.
166 	 * @param glyph: The glyph's info is loaded in to this object.
167 	 * @returns The glyph's bitmap data.
168 	 */
169 	std::unique_ptr<unsigned char[]> load_glyph(codepoint_t codepoint, Glyph &glyph) const;
170 
171 private:
172 	/**
173 	 * Initializes the font's face and creates a harfbuzz font instance.
174 	 *
175 	 * @param ft_library: The freetype library that should be used to load the font's face.
176 	 */
177 	void initialize(FT_Library ft_library);
178 
179 public:
180 	/**
181 	 * The description of the font.
182 	 * @see font_description
183 	 */
184 	font_description description;
185 
186 private:
187 	// Font's created without the use of FontManager are standalone and have their own FreeTypeLibrary instance
188 	std::unique_ptr<FreeTypeLibrary> freetype_library;
189 
190 	// The HarfBuzz font instance that drives the operations of this font
191 	hb_font_t *hb_font;
192 
193 };
194 
195 }} // openage::renderer
196 
197 namespace std {
198 
199 template<>
200 struct hash<openage::renderer::font_description> {
201 	size_t operator()(const openage::renderer::font_description &fd) const {
202 		size_t hash = std::hash<std::type_index>()(std::type_index(typeid(openage::renderer::font_description)));
203 		hash = openage::util::hash_combine(hash, std::hash<std::string>()(fd.font_file));
204 		hash = openage::util::hash_combine(hash, std::hash<unsigned int>()(fd.size));
205 		return hash;
206 	}
207 };
208 
209 }
210