1 | // LAF FreeType Wrapper |
2 | // Copyright (c) 2022 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_ALGORITHM_H_INCLUDED |
9 | #define FT_ALGORITHM_H_INCLUDED |
10 | #pragma once |
11 | |
12 | #include "base/string.h" |
13 | #include "base/utf8_decode.h" |
14 | #include "ft/freetype_headers.h" |
15 | #include "ft/hb_shaper.h" |
16 | #include "gfx/rect.h" |
17 | |
18 | namespace ft { |
19 | |
20 | template<typename FaceFT> |
21 | class DefaultShaper { |
22 | public: |
23 | using Glyph = typename FaceFT::Glyph; |
24 | |
25 | DefaultShaper(FaceFT& face, |
26 | const std::string& str) |
27 | : m_face(face) |
28 | , m_begin(str.begin()) |
29 | , m_decode(str) { |
30 | } |
31 | |
32 | int next() { |
33 | m_pos = m_decode.pos(); |
34 | return (m_char = m_decode.next()); |
35 | } |
36 | |
37 | int unicodeChar() const { |
38 | return m_char; |
39 | } |
40 | |
41 | int charIndex() const { |
42 | return m_pos - m_begin; |
43 | } |
44 | |
45 | unsigned int glyphIndex() { |
46 | return m_face.cache().getGlyphIndex(m_face, unicodeChar()); |
47 | } |
48 | |
49 | void glyphOffsetXY(Glyph* glyph) { |
50 | // Do nothing |
51 | } |
52 | |
53 | void glyphAdvanceXY(const Glyph* glyph, double& x, double& y) { |
54 | x += glyph->ft_glyph->advance.x / double(1 << 16); |
55 | y += glyph->ft_glyph->advance.y / double(1 << 16); |
56 | } |
57 | |
58 | private: |
59 | FaceFT& m_face; |
60 | std::string::const_iterator m_begin; |
61 | std::string::const_iterator m_pos; |
62 | base::utf8_decode m_decode; |
63 | int m_char = 0; |
64 | }; |
65 | |
66 | template<typename FaceFT, |
67 | typename Shaper = HBShaper<FaceFT> > |
68 | class ForEachGlyph { |
69 | public: |
70 | typedef typename FaceFT::Glyph Glyph; |
71 | |
72 | ForEachGlyph(FaceFT& face, const std::string& str) |
73 | : m_face(face) |
74 | , m_shaper(face, str) |
75 | , m_glyph(nullptr) |
76 | , m_useKerning(FT_HAS_KERNING(((FT_Face)face)) ? true: false) |
77 | , m_prevGlyph(0) |
78 | , m_x(0.0), m_y(0.0) { |
79 | } |
80 | |
81 | ~ForEachGlyph() { |
82 | unloadGlyph(); |
83 | } |
84 | |
85 | int unicodeChar() { return m_shaper.unicodeChar(); } |
86 | int charIndex() { return m_shaper.charIndex(); } |
87 | |
88 | const Glyph* glyph() const { return m_glyph; } |
89 | |
90 | int next() { |
91 | if (m_glyph) |
92 | m_prevGlyph = m_shaper.glyphIndex(); |
93 | |
94 | if (int chr = m_shaper.next()) { |
95 | prepareGlyph(); |
96 | return chr; |
97 | } |
98 | else |
99 | return 0; |
100 | } |
101 | |
102 | private: |
103 | void prepareGlyph() { |
104 | FT_UInt glyphIndex = m_shaper.glyphIndex(); |
105 | double initialX = m_x; |
106 | |
107 | if (m_useKerning && m_prevGlyph && glyphIndex) { |
108 | FT_Vector kerning; |
109 | FT_Get_Kerning(m_face, m_prevGlyph, glyphIndex, |
110 | FT_KERNING_DEFAULT, &kerning); |
111 | m_x += kerning.x / 64.0; |
112 | } |
113 | |
114 | unloadGlyph(); |
115 | |
116 | // Load new glyph |
117 | m_glyph = m_face.cache().loadGlyph(m_face, glyphIndex, m_face.antialias()); |
118 | if (m_glyph) { |
119 | m_glyph->bitmap = &FT_BitmapGlyph(m_glyph->ft_glyph)->bitmap; |
120 | m_glyph->x = m_x |
121 | + m_glyph->bearingX; |
122 | m_glyph->y = m_y |
123 | + m_face.height() |
124 | + m_face.descender() // descender is negative |
125 | - m_glyph->bearingY; |
126 | |
127 | m_shaper.glyphOffsetXY(m_glyph); |
128 | m_shaper.glyphAdvanceXY(m_glyph, m_x, m_y); |
129 | |
130 | m_glyph->startX = initialX; |
131 | m_glyph->endX = m_x; |
132 | } |
133 | } |
134 | |
135 | void unloadGlyph() { |
136 | if (m_glyph) { |
137 | m_face.cache().doneGlyph(m_glyph); |
138 | m_glyph = nullptr; |
139 | } |
140 | } |
141 | |
142 | private: |
143 | FaceFT& m_face; |
144 | Shaper m_shaper; |
145 | Glyph* m_glyph; |
146 | bool m_useKerning; |
147 | FT_UInt m_prevGlyph; |
148 | double m_x, m_y; |
149 | }; |
150 | |
151 | template<typename FaceFT> |
152 | gfx::Rect calc_text_bounds(FaceFT& face, const std::string& str) { |
153 | gfx::Rect bounds(0, 0, 0, 0); |
154 | ForEachGlyph<FaceFT> feg(face, str); |
155 | while (feg.next()) { |
156 | if (auto glyph = feg.glyph()) |
157 | bounds |= gfx::Rect(int(glyph->x), |
158 | int(glyph->y), |
159 | glyph->bitmap->width, |
160 | glyph->bitmap->rows); |
161 | } |
162 | return bounds; |
163 | } |
164 | |
165 | } // namespace ft |
166 | |
167 | #endif |
168 | |