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