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