1 | // LAF FreeType Wrapper |
2 | // Copyright (C) 2019 Igara Studio S.A. |
3 | // Copyright (C) 2016-2017 David Capello |
4 | // |
5 | // This file is released under the terms of the MIT license. |
6 | // Read LICENSE.txt for more information. |
7 | |
8 | #ifndef FT_FACE_H_INCLUDED |
9 | #define FT_FACE_H_INCLUDED |
10 | #pragma once |
11 | |
12 | #include "base/debug.h" |
13 | #include "base/disable_copying.h" |
14 | #include "ft/freetype_headers.h" |
15 | |
16 | #include <map> |
17 | |
18 | namespace ft { |
19 | |
20 | struct Glyph { |
21 | FT_UInt glyph_index; |
22 | FT_Glyph ft_glyph; |
23 | FT_Bitmap* bitmap; |
24 | double startX; |
25 | double endX; |
26 | double bearingX; |
27 | double bearingY; |
28 | double x; |
29 | double y; |
30 | }; |
31 | |
32 | template<typename Cache> |
33 | class FaceFT { |
34 | public: |
35 | typedef ft::Glyph Glyph; |
36 | |
37 | FaceFT(FT_Face face) : m_face(face) { |
38 | } |
39 | |
40 | ~FaceFT() { |
41 | if (m_face) |
42 | FT_Done_Face(m_face); |
43 | } |
44 | |
45 | operator FT_Face() { return m_face; } |
46 | FT_Face operator->() { return m_face; } |
47 | |
48 | bool isValid() const { |
49 | return (m_face != nullptr); |
50 | } |
51 | |
52 | bool antialias() const { |
53 | return m_antialias; |
54 | } |
55 | |
56 | void setAntialias(bool antialias) { |
57 | m_antialias = antialias; |
58 | m_cache.invalidate(); |
59 | } |
60 | |
61 | void setSize(int size) { |
62 | FT_Set_Pixel_Sizes(m_face, size, size); |
63 | m_cache.invalidate(); |
64 | } |
65 | |
66 | double height() const { |
67 | FT_Size_Metrics* metrics = &m_face->size->metrics; |
68 | double em_size = 1.0 * m_face->units_per_EM; |
69 | double y_scale = metrics->y_ppem / em_size; |
70 | return int(m_face->height * y_scale) - 1; |
71 | } |
72 | |
73 | double ascender() const { |
74 | FT_Size_Metrics* metrics = &m_face->size->metrics; |
75 | double em_size = 1.0 * m_face->units_per_EM; |
76 | double y_scale = metrics->y_ppem / em_size; |
77 | return int(m_face->ascender * y_scale); |
78 | } |
79 | |
80 | double descender() const { |
81 | FT_Size_Metrics* metrics = &m_face->size->metrics; |
82 | double em_size = 1.0 * m_face->units_per_EM; |
83 | double y_scale = metrics->y_ppem / em_size; |
84 | return int(m_face->descender * y_scale); |
85 | } |
86 | |
87 | bool hasCodePoint(int codepoint) const { |
88 | if (m_face) { |
89 | codepoint = FT_Get_Char_Index(m_face, codepoint); |
90 | return (codepoint != 0); |
91 | } |
92 | else |
93 | return false; |
94 | } |
95 | |
96 | Cache& cache() { return m_cache; } |
97 | |
98 | protected: |
99 | FT_Face m_face; |
100 | bool m_antialias; |
101 | Cache m_cache; |
102 | |
103 | private: |
104 | DISABLE_COPYING(FaceFT); |
105 | }; |
106 | |
107 | class NoCache { |
108 | public: |
109 | void invalidate() { |
110 | // Do nothing |
111 | } |
112 | |
113 | FT_UInt getGlyphIndex(FT_Face face, int charCode) { |
114 | return FT_Get_Char_Index(face, charCode); |
115 | } |
116 | |
117 | Glyph* loadGlyph(FT_Face face, FT_UInt glyphIndex, bool antialias) { |
118 | FT_Error err = FT_Load_Glyph( |
119 | face, glyphIndex, |
120 | FT_LOAD_RENDER | |
121 | // TODO Check if we can render correctly th embedded bitmaps |
122 | // in the future removing FT_LOAD_NO_BITMAP for fonts |
123 | // like Calibri, Cambria, Monaco, etc. |
124 | (antialias ? FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_BITMAP: |
125 | FT_LOAD_TARGET_MONO)); |
126 | if (err) |
127 | return nullptr; |
128 | |
129 | FT_Glyph ft_glyph; |
130 | err = FT_Get_Glyph(face->glyph, &ft_glyph); |
131 | if (err) |
132 | return nullptr; |
133 | |
134 | if (ft_glyph->format != FT_GLYPH_FORMAT_BITMAP) { |
135 | err = FT_Glyph_To_Bitmap(&ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1); |
136 | if (!err) { |
137 | FT_Done_Glyph(ft_glyph); |
138 | return nullptr; |
139 | } |
140 | } |
141 | |
142 | m_glyph.ft_glyph = ft_glyph; |
143 | m_glyph.bearingX = face->glyph->metrics.horiBearingX / 64.0; |
144 | m_glyph.bearingY = face->glyph->metrics.horiBearingY / 64.0; |
145 | |
146 | return &m_glyph; |
147 | } |
148 | |
149 | void doneGlyph(Glyph* glyph) { |
150 | ASSERT(glyph); |
151 | FT_Done_Glyph(glyph->ft_glyph); |
152 | } |
153 | |
154 | private: |
155 | Glyph m_glyph; |
156 | }; |
157 | |
158 | class SimpleCache : public NoCache { |
159 | public: |
160 | ~SimpleCache() { |
161 | invalidate(); |
162 | } |
163 | |
164 | void invalidate() { |
165 | for (auto& it : m_glyphMap) { |
166 | FT_Done_Glyph(it.second->ft_glyph); |
167 | delete it.second; |
168 | } |
169 | |
170 | m_glyphMap.clear(); |
171 | } |
172 | |
173 | Glyph* loadGlyph(FT_Face face, FT_UInt glyphIndex, bool antialias) { |
174 | auto it = m_glyphMap.find(glyphIndex); |
175 | if (it != m_glyphMap.end()) |
176 | return it->second; |
177 | |
178 | Glyph* glyph = NoCache::loadGlyph(face, glyphIndex, antialias); |
179 | if (!glyph) |
180 | return nullptr; |
181 | |
182 | FT_Glyph new_ft_glyph = nullptr; |
183 | FT_Glyph_Copy(glyph->ft_glyph, &new_ft_glyph); |
184 | if (!new_ft_glyph) |
185 | return nullptr; |
186 | |
187 | Glyph* newGlyph = new Glyph(*glyph); |
188 | newGlyph->ft_glyph = new_ft_glyph; |
189 | |
190 | m_glyphMap[glyphIndex] = newGlyph; |
191 | FT_Done_Glyph(glyph->ft_glyph); |
192 | |
193 | return newGlyph; |
194 | } |
195 | |
196 | void doneGlyph(Glyph* glyph) { |
197 | // Do nothing |
198 | } |
199 | |
200 | private: |
201 | std::map<FT_UInt, Glyph*> m_glyphMap; |
202 | }; |
203 | |
204 | } // namespace ft |
205 | |
206 | #endif |
207 | |