1 /*
2 * Copyright © 2023 Google, Inc.
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 * Google Author(s): Qunxin Liu
25 */
26
27 #include <math.h>
28 #include "hb-subset-instancer-solver.hh"
29
approx(Triple a,Triple b)30 static inline bool approx (Triple a, Triple b)
31 {
32 return abs (a.minimum - b.minimum) < 0.000001 &&
33 abs (a.middle - b.middle) < 0.000001 &&
34 abs (a.maximum - b.maximum) < 0.000001;
35 }
36
approx(double a,double b)37 static inline bool approx (double a, double b)
38 { return abs (a - b) < 0.000001; }
39
40 /* tests ported from
41 * https://github.com/fonttools/fonttools/blob/main/Tests/varLib/instancer/solver_test.py */
42 int
main(int argc,char ** argv)43 main (int argc, char **argv)
44 {
45 TripleDistances default_axis_distances{1.0, 1.0};
46 /* Case 1 */
47 {
48 /* pin axis*/
49 Triple tent (0.0, 1.0, 1.0);
50 Triple axis_range (0.0, 0.0, 0.0);
51 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
52 assert (out.length == 0);
53 }
54
55 {
56 /* pin axis*/
57 Triple tent (0.0, 1.0, 1.0);
58 Triple axis_range (0.5, 0.5, 0.5);
59 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
60 assert (out.length == 1);
61 assert (out[0].first == 0.5);
62 assert (out[0].second == Triple ());
63 }
64
65 {
66 /* tent falls outside the new axis range */
67 Triple tent (0.3, 0.5, 0.8);
68 Triple axis_range (0.1, 0.2, 0.3);
69 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
70 assert (out.length == 0);
71 }
72
73 /* Case 2 */
74 {
75 Triple tent (0.0, 1.0, 1.0);
76 Triple axis_range (-1.0, 0.0, 0.5);
77 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
78 assert (out.length == 1);
79 assert (out[0].first == 0.5);
80 assert (out[0].second == Triple (0.0, 1.0, 1.0));
81 }
82
83 /* Case 2 */
84 {
85 Triple tent (0.0, 1.0, 1.0);
86 Triple axis_range (-1.0, 0.0, 0.75);
87 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
88 assert (out.length == 1);
89 assert (out[0].first == 0.75);
90 assert (out[0].second == Triple (0.0, 1.0, 1.0));
91 }
92
93 /* Without gain: */
94 /* Case 3 */
95 {
96 Triple tent (0.0, 0.2, 1.0);
97 Triple axis_range (-1.0, 0.0, 0.8);
98 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
99 assert (out.length == 2);
100 assert (out[0].first == 1.0);
101 assert (out[0].second == Triple (0.0, 0.25, 1.0));
102 assert (approx (out[1].first, 0.250));
103 assert (out[1].second == Triple (0.25, 1.0, 1.0));
104 }
105
106 /* Case 3 boundary */
107 {
108 Triple tent (0.0, 0.4, 1.0);
109 Triple axis_range (-1.0, 0.0, 0.5);
110 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
111 assert (out.length == 2);
112 assert (out[0].first == 1.0);
113 assert (out[0].second == Triple (0.0, 0.8, 1.0));
114 assert (approx (out[1].first, 2.5/3));
115 assert (out[1].second == Triple (0.8, 1.0, 1.0));
116 }
117
118 /* Case 4 */
119 {
120 Triple tent (0.0, 0.25, 1.0);
121 Triple axis_range (-1.0, 0.0, 0.4);
122 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
123 assert (out.length == 2);
124 assert (out[0].first == 1.0);
125 assert (out[0].second == Triple (0.0, 0.625, 1.0));
126 assert (approx (out[1].first, 0.80));
127 assert (out[1].second == Triple (0.625, 1.0, 1.0));
128 }
129
130 /* Case 4 */
131 {
132 Triple tent (0.25, 0.3, 1.05);
133 Triple axis_range (0.0, 0.2, 0.4);
134 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
135 assert (out.length == 2);
136 assert (out[0].first == 1.0);
137 assert (approx (out[0].second, Triple (0.25, 0.5, 1.0)));
138 assert (approx (out[1].first, 2.6 / 3));
139 assert (approx (out[1].second, Triple (0.5, 1.0, 1.0)));
140 }
141
142 /* Case 4 boundary */
143 {
144 Triple tent (0.25, 0.5, 1.0);
145 Triple axis_range (0.0, 0.25, 0.5);
146 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
147 assert (out.length == 1);
148 assert (out[0].first == 1.0);
149 assert (out[0].second == Triple (0.0, 1.0, 1.0));
150 }
151
152 /* With gain */
153 /* Case 3a/1neg */
154 {
155 Triple tent (0.0, 0.5, 1.0);
156 Triple axis_range (0.0, 0.5, 1.0);
157 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
158 assert (out.length == 3);
159 assert (out[0].first == 1.0);
160 assert (out[0].second == Triple ());
161 assert (out[1].first == -1.0);
162 assert (out[1].second == Triple (0.0, 1.0, 1.0));
163 assert (out[2].first == -1.0);
164 assert (out[2].second == Triple (-1.0, -1.0, 0.0));
165 }
166
167 {
168 Triple tent (0.0, 0.5, 1.0);
169 Triple axis_range (0.0, 0.5, 0.75);
170 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
171 assert (out.length == 3);
172 assert (out[0].first == 1.0);
173 assert (out[0].second == Triple ());
174 assert (out[1].first == -0.5);
175 assert (out[1].second == Triple (0.0, 1.0, 1.0));
176 assert (out[2].first == -1.0);
177 assert (out[2].second == Triple (-1.0, -1.0, 0.0));
178 }
179
180 {
181 Triple tent (0.0, 0.50, 1.0);
182 Triple axis_range (0.0, 0.25, 0.8);
183 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
184 assert (out.length == 4);
185 assert (out[0].first == 0.5);
186 assert (out[0].second == Triple ());
187 assert (out[1].first == 0.5);
188 assert (approx (out[1].second, Triple (0.0, 0.454545, 0.909091)));
189 assert (approx (out[2].first, -0.1));
190 assert (approx (out[2].second, Triple (0.909091, 1.0, 1.0)));
191 assert (out[3].first == -0.5);
192 assert (out[3].second == Triple (-1.0, -1.0, 0.0));
193 }
194
195 /* Case 3a/1neg */
196 {
197 Triple tent (0.0, 0.5, 2.0);
198 Triple axis_range (0.2, 0.5, 0.8);
199 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
200 assert (out.length == 3);
201 assert (out[0].first == 1.0);
202 assert (out[0].second == Triple ());
203 assert (approx (out[1].first, -0.2));
204 assert (out[1].second == Triple (0.0, 1.0, 1.0));
205 assert (approx (out[2].first, -0.6));
206 assert (out[2].second == Triple (-1.0, -1.0, 0.0));
207 }
208
209 /* Case 3a/1neg */
210 {
211 Triple tent (0.0, 0.5, 2.0);
212 Triple axis_range (0.2, 0.5, 1.0);
213 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
214 assert (out.length == 3);
215 assert (out[0].first == 1.0);
216 assert (out[0].second == Triple ());
217 assert (approx (out[1].first, -1.0/3));
218 assert (out[1].second == Triple (0.0, 1.0, 1.0));
219 assert (approx (out[2].first, -0.6));
220 assert (out[2].second == Triple (-1.0, -1.0, 0.0));
221 }
222
223 /* Case 3 */
224 {
225 Triple tent (0.0, 0.5, 1.0);
226 Triple axis_range (0.25, 0.25, 0.75);
227 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
228 assert (out.length == 2);
229 assert (out[0].first == 0.5);
230 assert (out[0].second == Triple ());
231 assert (out[1].first == 0.5);
232 assert (out[1].second == Triple (0.0, 0.5, 1.0));
233 }
234
235 /* Case 1neg */
236 {
237 Triple tent (0.0, 0.5, 1.0);
238 Triple axis_range (0.0, 0.25, 0.5);
239 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
240 assert (out.length == 3);
241 assert (out[0].first == 0.5);
242 assert (out[0].second == Triple ());
243 assert (out[1].first == 0.5);
244 assert (out[1].second == Triple (0.0, 1.0, 1.0));
245 assert (out[2].first == -0.5);
246 assert (out[2].second == Triple (-1.0, -1.0, 0.0));
247 }
248
249 /* Case 2neg */
250 {
251 Triple tent (0.05, 0.55, 1.0);
252 Triple axis_range (0.0, 0.25, 0.5);
253 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
254 assert (out.length == 4);
255 assert (approx (out[0].first, 0.4));
256 assert (out[0].second == Triple ());
257 assert (approx (out[1].first, 0.5));
258 assert (out[1].second == Triple (0.0, 1.0, 1.0));
259 assert (approx (out[2].first, -0.4));
260 assert (out[2].second == Triple (-1.0, -0.8, 0.0));
261 assert (approx (out[3].first, -0.4));
262 assert (out[3].second == Triple (-1.0, -1.0, -0.8));
263 }
264
265 /* Case 2neg, other side */
266 {
267 Triple tent (-1.0, -0.55, -0.05);
268 Triple axis_range (-0.5, -0.25, 0.0);
269 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
270 assert (out.length == 4);
271 assert (approx (out[0].first, 0.4));
272 assert (out[0].second == Triple ());
273 assert (approx (out[1].first, 0.5));
274 assert (out[1].second == Triple (-1.0, -1.0, 0.0));
275 assert (approx (out[2].first, -0.4));
276 assert (out[2].second == Triple (0.0, 0.8, 1.0));
277 assert (approx (out[3].first, -0.4));
278 assert (out[3].second == Triple (0.8, 1.0, 1.0));
279 }
280
281 /* Misc corner cases */
282 {
283 Triple tent (0.5, 0.5, 0.5);
284 Triple axis_range (0.5, 0.5, 0.5);
285 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
286 assert (out.length == 1);
287 assert (out[0].first == 1.0);
288 assert (out[0].second == Triple ());
289 }
290
291 {
292 Triple tent (0.3, 0.5, 0.7);
293 Triple axis_range (0.1, 0.5, 0.9);
294 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
295 assert (out.length == 5);
296 assert (out[0].first == 1.0);
297 assert (out[0].second == Triple ());
298 assert (out[1].first == -1.0);
299 assert (approx(out[1].second, Triple (0.0, 0.5, 1.0)));
300 assert (out[2].first == -1.0);
301 assert (approx(out[2].second, Triple (0.5, 1.0, 1.0)));
302 assert (out[3].first == -1.0);
303 assert (approx (out[3].second, Triple (-1.0, -0.5, 0.0)));
304 assert (out[4].first == -1.0);
305 assert (approx (out[4].second, Triple (-1.0, -1.0, -0.5)));
306 }
307
308 {
309 Triple tent (0.5, 0.5, 0.5);
310 Triple axis_range (0.25, 0.25, 0.5);
311 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
312 assert (out.length == 1);
313 assert (out[0].first == 1.0);
314 assert (out[0].second == Triple (1.0, 1.0, 1.0));
315 }
316
317 {
318 Triple tent (0.5, 0.5, 0.5);
319 Triple axis_range (0.25, 0.35, 0.5);
320 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
321 assert (out.length == 1);
322 assert (out[0].first == 1.0);
323 assert (out[0].second == Triple (1.0, 1.0, 1.0));
324 }
325
326 {
327 Triple tent (0.5, 0.5, 0.55);
328 Triple axis_range (0.25, 0.35, 0.5);
329 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
330 assert (out.length == 1);
331 assert (out[0].first == 1.0);
332 assert (out[0].second == Triple (1.0, 1.0, 1.0));
333 }
334
335 {
336 Triple tent (0.5, 0.5, 1.0);
337 Triple axis_range (0.5, 0.5, 1.0);
338 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
339 assert (out.length == 2);
340 assert (out[0].first == 1.0);
341 assert (out[0].second == Triple ());
342 assert (out[1].first == -1.0);
343 assert (out[1].second == Triple (0.0, 1.0, 1.0));
344 }
345
346 {
347 Triple tent (0.25, 0.5, 1.0);
348 Triple axis_range (0.5, 0.5, 1.0);
349 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
350 assert (out.length == 2);
351 assert (out[0].first == 1.0);
352 assert (out[0].second == Triple ());
353 assert (out[1].first == -1.0);
354 assert (out[1].second == Triple (0.0, 1.0, 1.0));
355 }
356
357 {
358 Triple tent (0.0, 0.2, 1.0);
359 Triple axis_range (0.0, 0.0, 0.5);
360 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
361 assert (out.length == 2);
362 assert (out[0].first == 1.0);
363 assert (out[0].second == Triple (0.0, 0.4, 1.0));
364 assert (out[1].first == 0.625);
365 assert (out[1].second == Triple (0.4, 1.0, 1.0));
366 }
367
368
369 {
370 Triple tent (0.0, 0.5, 1.0);
371 Triple axis_range (-1.0, 0.25, 1.0);
372 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
373 assert (out.length == 5);
374 assert (out[0].first == 0.5);
375 assert (out[0].second == Triple ());
376 assert (out[1].first == 0.5);
377 assert (out[1].second == Triple (0.0, 1.0/3, 2.0/3));
378 assert (out[2].first == -0.5);
379 assert (out[2].second == Triple (2.0/3, 1.0, 1.0));
380 assert (out[3].first == -0.5);
381 assert (out[3].second == Triple (-1.0, -0.2, 0.0));
382 assert (out[4].first == -0.5);
383 assert (out[4].second == Triple (-1.0, -1.0, -0.2));
384 }
385
386 {
387 Triple tent (0.5, 0.5, 0.5);
388 Triple axis_range (0.0, 0.5, 1.0);
389 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
390 assert (out.length == 5);
391 assert (out[0].first == 1.0);
392 assert (out[0].second == Triple ());
393 assert (out[1].first == -1.0);
394 assert (out[1].second == Triple (0.0, 2/(double) (1 << 14), 1.0));
395 assert (out[2].first == -1.0);
396 assert (out[2].second == Triple (2/(double) (1 << 14), 1.0, 1.0));
397 assert (out[3].first == -1.0);
398 assert (out[3].second == Triple (-1.0, -2/(double) (1 << 14), 0.0));
399 assert (out[4].first == -1.0);
400 assert (out[4].second == Triple (-1.0, -1.0, -2/(double) (1 << 14)));
401 }
402
403 {
404 Triple tent (0.0, 1.0, 1.0);
405 Triple axis_range (-1.0, -0.5, 1.0);
406 rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances);
407 assert (out.length == 1);
408 assert (out[0].first == 1.0);
409 assert (out[0].second == Triple (1.0/3, 1.0, 1.0));
410 }
411
412 {
413 Triple tent (0.0, 1.0, 1.0);
414 Triple axis_range (-1.0, -0.5, 1.0);
415 TripleDistances axis_distances{2.0, 1.0};
416 rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances);
417 assert (out.length == 1);
418 assert (out[0].first == 1.0);
419 assert (out[0].second == Triple (0.5, 1.0, 1.0));
420 }
421
422 {
423 Triple tent (0.6, 0.7, 0.8);
424 Triple axis_range (-1.0, 0.2, 1.0);
425 TripleDistances axis_distances{1.0, 1.0};
426 rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances);
427 assert (out.length == 1);
428 assert (out[0].first == 1.0);
429 assert (approx (out[0].second, Triple (0.5, 0.625, 0.75)));
430 }
431 }
432