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
18namespace 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