1
+ #include < cstdint>
2
+ #include < math.h>
3
+ #include < string.h>
4
+ #include < algorithm>
5
+ #include < vector>
6
+ #include < optional>
7
+ #include < map>
8
+
9
+ #include " alright_fonts.hpp"
10
+
11
+ using namespace pretty_poly ;
12
+
13
+ namespace alright_fonts {
14
+ /*
15
+ utility functions
16
+ */
17
+ pretty_poly::rect_t measure_character (text_metrics_t &tm, uint16_t codepoint) {
18
+ if (tm.face .glyphs .count (codepoint) == 1 ) {
19
+ glyph_t glyph = tm.face .glyphs [codepoint];
20
+
21
+ return {0 , 0 , ((glyph.advance * tm.size ) / 128 ), tm.size };
22
+ }
23
+
24
+ return {0 , 0 , 0 , 0 };
25
+ }
26
+
27
+ /*
28
+ render functions
29
+ */
30
+
31
+ void render_character (text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t <int > origin) {
32
+ if (tm.face .glyphs .count (codepoint) == 1 ) {
33
+ glyph_t glyph = tm.face .glyphs [codepoint];
34
+
35
+ // scale is a fixed point 16:16 value, our font data is already scaled to
36
+ // -128..127 so to get the pixel size we want we can just shift the
37
+ // users requested size up one bit
38
+ unsigned scale = tm.size << 9 ;
39
+
40
+ pretty_poly::draw_polygon<int8_t >(glyph.contours , origin, scale);
41
+ }
42
+ }
43
+
44
+ void render_character (text_metrics_t &tm, uint16_t codepoint, pretty_poly::point_t <int > origin, pretty_poly::mat3_t transform) {
45
+ if (tm.face .glyphs .count (codepoint) == 1 ) {
46
+ glyph_t glyph = tm.face .glyphs [codepoint];
47
+
48
+ // scale is a fixed point 16:16 value, our font data is already scaled to
49
+ // -128..127 so to get the pixel size we want we can just shift the
50
+ // users requested size up one bit
51
+ unsigned scale = tm.size << 9 ;
52
+
53
+ std::vector<pretty_poly::contour_t <int8_t >> contours;
54
+
55
+ for (auto i = 0u ; i < glyph.contours .size (); i++) {
56
+ unsigned int count = glyph.contours [i].count ;
57
+ point_t <int8_t > *points = (point_t <int8_t > *)malloc (sizeof (point_t <int8_t >) * count);
58
+ for (auto j = 0u ; j < count; j++) {
59
+ point_t <float > point (glyph.contours [i].points [j].x , glyph.contours [i].points [j].y );
60
+ point *= transform;
61
+ points[j] = point_t <int8_t >(point.x , point.y );
62
+ }
63
+ contours.emplace_back (points, count);
64
+ }
65
+
66
+ pretty_poly::draw_polygon<int8_t >(contours, origin, scale);
67
+
68
+ for (auto contour : contours) {
69
+ free (contour.points );
70
+ }
71
+ }
72
+ }
73
+
74
+ /*
75
+ load functions
76
+ */
77
+
78
+ // big endian stream value helpers
79
+ uint16_t ru16 (file_io &ifs) {uint8_t w[2 ]; ifs.read ((char *)w, 2 ); return w[0 ] << 8 | w[1 ];}
80
+ int16_t rs16 (file_io &ifs) {uint8_t w[2 ]; ifs.read ((char *)w, 2 ); return w[0 ] << 8 | w[1 ];}
81
+ uint32_t ru32 (file_io &ifs) {uint8_t dw[4 ]; ifs.read ((char *)dw, 4 ); return dw[0 ] << 24 | dw[1 ] << 16 | dw[2 ] << 8 | dw[3 ];}
82
+ uint8_t ru8 (file_io &ifs) {uint8_t w; ifs.read (&w, 1 ); return w;}
83
+ int8_t rs8 (file_io &ifs) {int8_t w; ifs.read (&w, 1 ); return w;}
84
+
85
+ bool face_t::load (file_io &ifs) {
86
+ char marker[4 ];
87
+ ifs.read (marker, sizeof (marker));
88
+
89
+ // check header magic bytes are present
90
+ if (memcmp (marker, " af!?" , 4 ) != 0 ) {
91
+ // doesn't start with magic marker
92
+ return false ;
93
+ }
94
+
95
+ // number of glyphs embedded in font file
96
+ this ->glyph_count = ru16 (ifs);
97
+
98
+ // extract flags and ensure none set
99
+ this ->flags = ru16 (ifs);
100
+ if (this ->flags != 0 ) {
101
+ // unknown flags set
102
+ return false ;
103
+ }
104
+
105
+ // extract glyph dictionary
106
+ uint16_t glyph_entry_size = 9 ;
107
+ uint32_t contour_data_offset = 8 + this ->glyph_count * glyph_entry_size;
108
+ for (auto i = 0 ; i < this ->glyph_count ; i++) {
109
+ glyph_t g;
110
+ g.codepoint = ru16 (ifs);
111
+ g.bounds .x = rs8 (ifs);
112
+ g.bounds .y = rs8 (ifs);
113
+ g.bounds .w = ru8 (ifs);
114
+ g.bounds .h = ru8 (ifs);
115
+ g.advance = ru8 (ifs);
116
+
117
+ if (ifs.fail ()) {
118
+ // could not read glyph dictionary entry
119
+ return false ;
120
+ }
121
+
122
+ // allocate space for the contour data and read it from the font file
123
+ uint16_t contour_data_length = ru16 (ifs);
124
+
125
+ // remember where we are in the dictionary
126
+ int pos = ifs.tell ();
127
+
128
+ // read contour data
129
+ ifs.seek (contour_data_offset);
130
+ while (true ) {
131
+ // get number of points in contour
132
+ uint16_t count = ru16 (ifs);
133
+
134
+ // if count is zero then this is the end of contour marker
135
+ if (count == 0 ) {
136
+ break ;
137
+ }
138
+
139
+ // allocate space to store point data for contour and read
140
+ // from file
141
+ pretty_poly::point_t <int8_t > *points = new pretty_poly::point_t <int8_t >[count];
142
+ ifs.read ((char *)points, count * 2 );
143
+
144
+ g.contours .push_back ({points, count});
145
+ }
146
+
147
+ // return back to position in dictionary
148
+ ifs.seek (pos);
149
+ contour_data_offset += contour_data_length;
150
+
151
+ if (ifs.fail ()) {
152
+ // could not read glyph contour data
153
+ return false ;
154
+ }
155
+
156
+ this ->glyphs [g.codepoint ] = g;
157
+ }
158
+
159
+ return true ;
160
+ }
161
+
162
+ bool face_t::load (std::string_view path) {
163
+ file_io ifs (path);
164
+ if (ifs.fail ()) {
165
+ // could not open file
166
+ return false ;
167
+ }
168
+ return load (ifs);
169
+ }
170
+
171
+ }
0 commit comments