1 /*
2 * Copyright © 2024 Behdad Esfahbod
3 *
4 * This is part of HarfBuzz, a text shaping library.
5 *
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
11 *
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
16 * DAMAGE.
17 *
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
23 */
24
25 #include "hb-test.h"
26 #include <math.h>
27
28 #include <hb.h>
29
30 typedef struct draw_data_t
31 {
32 unsigned move_to_count;
33 unsigned line_to_count;
34 unsigned quad_to_count;
35 unsigned cubic_to_count;
36 unsigned close_path_count;
37 } draw_data_t;
38
39 /* Our modified itoa, why not using libc's? it is going to be used
40 in harfbuzzjs where libc isn't available */
_hb_reverse(char * buf,unsigned int len)41 static void _hb_reverse (char *buf, unsigned int len)
42 {
43 unsigned start = 0, end = len - 1;
44 while (start < end)
45 {
46 char c = buf[end];
47 buf[end] = buf[start];
48 buf[start] = c;
49 start++; end--;
50 }
51 }
_hb_itoa(float fnum,char * buf)52 static unsigned _hb_itoa (float fnum, char *buf)
53 {
54 int32_t num = (int32_t) floorf (fnum + .5f);
55 unsigned int i = 0;
56 hb_bool_t is_negative = num < 0;
57 if (is_negative) num = -num;
58 do
59 {
60 buf[i++] = '0' + num % 10;
61 num /= 10;
62 } while (num);
63 if (is_negative) buf[i++] = '-';
64 _hb_reverse (buf, i);
65 buf[i] = '\0';
66 return i;
67 }
68
69 #define ITOA_BUF_SIZE 12 // 10 digits in int32, 1 for negative sign, 1 for \0
70
71 static void
test_itoa(void)72 test_itoa (void)
73 {
74 char s[] = "12345";
75 _hb_reverse (s, 5);
76 g_assert_cmpmem (s, 5, "54321", 5);
77
78 {
79 unsigned num = 12345;
80 char buf[ITOA_BUF_SIZE];
81 unsigned len = _hb_itoa (num, buf);
82 g_assert_cmpmem (buf, len, "12345", 5);
83 }
84
85 {
86 unsigned num = 3152;
87 char buf[ITOA_BUF_SIZE];
88 unsigned len = _hb_itoa (num, buf);
89 g_assert_cmpmem (buf, len, "3152", 4);
90 }
91
92 {
93 int num = -6457;
94 char buf[ITOA_BUF_SIZE];
95 unsigned len = _hb_itoa (num, buf);
96 g_assert_cmpmem (buf, len, "-6457", 5);
97 }
98 }
99
100 static void
move_to(HB_UNUSED hb_draw_funcs_t * dfuncs,draw_data_t * draw_data,HB_UNUSED hb_draw_state_t * st,HB_UNUSED float to_x,HB_UNUSED float to_y,HB_UNUSED void * user_data)101 move_to (HB_UNUSED hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
102 HB_UNUSED hb_draw_state_t *st,
103 HB_UNUSED float to_x, HB_UNUSED float to_y,
104 HB_UNUSED void *user_data)
105 {
106 draw_data->move_to_count++;
107 }
108
109 static void
line_to(HB_UNUSED hb_draw_funcs_t * dfuncs,draw_data_t * draw_data,HB_UNUSED hb_draw_state_t * st,HB_UNUSED float to_x,HB_UNUSED float to_y,HB_UNUSED void * user_data)110 line_to (HB_UNUSED hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
111 HB_UNUSED hb_draw_state_t *st,
112 HB_UNUSED float to_x, HB_UNUSED float to_y,
113 HB_UNUSED void *user_data)
114 {
115 draw_data->line_to_count++;
116 }
117
118 static void
quadratic_to(HB_UNUSED hb_draw_funcs_t * dfuncs,draw_data_t * draw_data,HB_UNUSED hb_draw_state_t * st,HB_UNUSED float control_x,HB_UNUSED float control_y,HB_UNUSED float to_x,HB_UNUSED float to_y,HB_UNUSED void * user_data)119 quadratic_to (HB_UNUSED hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
120 HB_UNUSED hb_draw_state_t *st,
121 HB_UNUSED float control_x, HB_UNUSED float control_y,
122 HB_UNUSED float to_x, HB_UNUSED float to_y,
123 HB_UNUSED void *user_data)
124 {
125 draw_data->quad_to_count++;
126 }
127
128 static void
cubic_to(HB_UNUSED hb_draw_funcs_t * dfuncs,draw_data_t * draw_data,HB_UNUSED hb_draw_state_t * st,HB_UNUSED float control1_x,HB_UNUSED float control1_y,HB_UNUSED float control2_x,HB_UNUSED float control2_y,HB_UNUSED float to_x,HB_UNUSED float to_y,HB_UNUSED void * user_data)129 cubic_to (HB_UNUSED hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
130 HB_UNUSED hb_draw_state_t *st,
131 HB_UNUSED float control1_x, HB_UNUSED float control1_y,
132 HB_UNUSED float control2_x, HB_UNUSED float control2_y,
133 HB_UNUSED float to_x, HB_UNUSED float to_y,
134 HB_UNUSED void *user_data)
135 {
136 draw_data->cubic_to_count++;
137 }
138
139 static void
close_path(HB_UNUSED hb_draw_funcs_t * dfuncs,draw_data_t * draw_data,HB_UNUSED hb_draw_state_t * st,HB_UNUSED void * user_data)140 close_path (HB_UNUSED hb_draw_funcs_t *dfuncs, draw_data_t *draw_data,
141 HB_UNUSED hb_draw_state_t *st,
142 HB_UNUSED void *user_data)
143 {
144 draw_data->close_path_count++;
145 }
146
147 static hb_draw_funcs_t *funcs;
148
149 #ifdef HB_EXPERIMENTAL_API
150 static void
test_hb_draw_varc_simple_hangul(void)151 test_hb_draw_varc_simple_hangul (void)
152 {
153 hb_face_t *face = hb_test_open_font_file ("fonts/varc-ac00-ac01.ttf");
154 hb_font_t *font = hb_font_create (face);
155 hb_face_destroy (face);
156
157 draw_data_t draw_data0 = {0};
158 draw_data_t draw_data;;
159 unsigned gid = 0;
160
161 hb_font_get_nominal_glyph (font, 0xAC00u, &gid);
162 draw_data = draw_data0;
163 hb_font_draw_glyph (font, gid, funcs, &draw_data);
164 g_assert_cmpuint (draw_data.move_to_count, ==, 3);
165
166 hb_font_get_nominal_glyph (font, 0xAC01u, &gid);
167 draw_data = draw_data0;
168 hb_font_draw_glyph (font, gid, funcs, &draw_data);
169 g_assert_cmpuint (draw_data.move_to_count, ==, 4);
170
171 hb_variation_t var;
172 var.tag = HB_TAG ('w','g','h','t');
173 var.value = 800;
174 hb_font_set_variations (font, &var, 1);
175
176 hb_font_get_nominal_glyph (font, 0xAC00u, &gid);
177 draw_data = draw_data0;
178 hb_font_draw_glyph (font, gid, funcs, &draw_data);
179 g_assert_cmpuint (draw_data.move_to_count, ==, 3);
180
181 hb_font_get_nominal_glyph (font, 0xAC01u, &gid);
182 draw_data = draw_data0;
183 hb_font_draw_glyph (font, gid, funcs, &draw_data);
184 g_assert_cmpuint (draw_data.move_to_count, ==, 4);
185
186 hb_font_destroy (font);
187 }
188
189 static void
test_hb_draw_varc_simple_hanzi(void)190 test_hb_draw_varc_simple_hanzi (void)
191 {
192 hb_face_t *face = hb_test_open_font_file ("fonts/varc-6868.ttf");
193 hb_font_t *font = hb_font_create (face);
194 hb_face_destroy (face);
195
196 draw_data_t draw_data0 = {0};
197 draw_data_t draw_data;;
198 unsigned gid = 0;
199
200 hb_font_get_nominal_glyph (font, 0x6868u, &gid);
201 draw_data = draw_data0;
202 hb_font_draw_glyph (font, gid, funcs, &draw_data);
203 g_assert_cmpuint (draw_data.move_to_count, ==, 11);
204
205 hb_variation_t var;
206 var.tag = HB_TAG ('w','g','h','t');
207 var.value = 800;
208 hb_font_set_variations (font, &var, 1);
209
210 hb_font_get_nominal_glyph (font, 0x6868u, &gid);
211 draw_data = draw_data0;
212 hb_font_draw_glyph (font, gid, funcs, &draw_data);
213 g_assert_cmpuint (draw_data.move_to_count, ==, 11);
214
215 hb_font_destroy (font);
216 }
217
218 static void
test_hb_draw_varc_conditional(void)219 test_hb_draw_varc_conditional (void)
220 {
221 hb_face_t *face = hb_test_open_font_file ("fonts/varc-ac01-conditional.ttf");
222 hb_font_t *font = hb_font_create (face);
223 hb_face_destroy (face);
224
225 draw_data_t draw_data0 = {0};
226 draw_data_t draw_data;;
227 unsigned gid = 0;
228
229 hb_font_get_nominal_glyph (font, 0xAC01u, &gid);
230 draw_data = draw_data0;
231 hb_font_draw_glyph (font, gid, funcs, &draw_data);
232 g_assert_cmpuint (draw_data.move_to_count, ==, 2);
233
234 hb_variation_t var;
235 var.tag = HB_TAG ('w','g','h','t');
236 var.value = 800;
237 hb_font_set_variations (font, &var, 1);
238
239 hb_font_get_nominal_glyph (font, 0xAC01u, &gid);
240 draw_data = draw_data0;
241 hb_font_draw_glyph (font, gid, funcs, &draw_data);
242 g_assert_cmpuint (draw_data.move_to_count, ==, 4);
243
244 hb_font_destroy (font);
245 }
246 #endif
247
248 int
main(int argc,char ** argv)249 main (int argc, char **argv)
250 {
251 funcs = hb_draw_funcs_create ();
252 hb_draw_funcs_set_move_to_func (funcs, (hb_draw_move_to_func_t) move_to, NULL, NULL);
253 hb_draw_funcs_set_line_to_func (funcs, (hb_draw_line_to_func_t) line_to, NULL, NULL);
254 hb_draw_funcs_set_quadratic_to_func (funcs, (hb_draw_quadratic_to_func_t) quadratic_to, NULL, NULL);
255 hb_draw_funcs_set_cubic_to_func (funcs, (hb_draw_cubic_to_func_t) cubic_to, NULL, NULL);
256 hb_draw_funcs_set_close_path_func (funcs, (hb_draw_close_path_func_t) close_path, NULL, NULL);
257 hb_draw_funcs_make_immutable (funcs);
258
259 hb_test_init (&argc, &argv);
260 hb_test_add (test_itoa);
261 #ifdef HB_EXPERIMENTAL_API
262 hb_test_add (test_hb_draw_varc_simple_hangul);
263 hb_test_add (test_hb_draw_varc_simple_hanzi);
264 hb_test_add (test_hb_draw_varc_conditional);
265 #endif
266 unsigned result = hb_test_run ();
267
268 hb_draw_funcs_destroy (funcs);
269 return result;
270 }
271