| /* |
| * Copyright © 2023 Google, Inc. |
| * |
| * This is part of HarfBuzz, a text shaping library. |
| * |
| * Permission is hereby granted, without written agreement and without |
| * license or royalty fees, to use, copy, modify, and distribute this |
| * software and its documentation for any purpose, provided that the |
| * above copyright notice and the following two paragraphs appear in |
| * all copies of this software. |
| * |
| * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
| * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
| * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
| * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
| * DAMAGE. |
| * |
| * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
| * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
| * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
| * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
| * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
| * |
| * Google Author(s): Qunxin Liu |
| */ |
| |
| #include <math.h> |
| #include "hb-subset-instancer-solver.hh" |
| |
| static inline bool approx (Triple a, Triple b) |
| { |
| return abs (a.minimum - b.minimum) < 0.000001 && |
| abs (a.middle - b.middle) < 0.000001 && |
| abs (a.maximum - b.maximum) < 0.000001; |
| } |
| |
| static inline bool approx (double a, double b) |
| { return abs (a - b) < 0.000001; } |
| |
| /* tests ported from |
| * https://github.com/fonttools/fonttools/blob/main/Tests/varLib/instancer/solver_test.py */ |
| int |
| main (int argc, char **argv) |
| { |
| TripleDistances default_axis_distances{1.0, 1.0}; |
| /* Case 1 */ |
| { |
| /* pin axis*/ |
| Triple tent (0.0, 1.0, 1.0); |
| Triple axis_range (0.0, 0.0, 0.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 0); |
| } |
| |
| { |
| /* pin axis*/ |
| Triple tent (0.0, 1.0, 1.0); |
| Triple axis_range (0.5, 0.5, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 0.5); |
| assert (out[0].second == Triple ()); |
| } |
| |
| { |
| /* tent falls outside the new axis range */ |
| Triple tent (0.3, 0.5, 0.8); |
| Triple axis_range (0.1, 0.2, 0.3); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 0); |
| } |
| |
| /* Case 2 */ |
| { |
| Triple tent (0.0, 1.0, 1.0); |
| Triple axis_range (-1.0, 0.0, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 0.5); |
| assert (out[0].second == Triple (0.0, 1.0, 1.0)); |
| } |
| |
| /* Case 2 */ |
| { |
| Triple tent (0.0, 1.0, 1.0); |
| Triple axis_range (-1.0, 0.0, 0.75); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 0.75); |
| assert (out[0].second == Triple (0.0, 1.0, 1.0)); |
| } |
| |
| /* Without gain: */ |
| /* Case 3 */ |
| { |
| Triple tent (0.0, 0.2, 1.0); |
| Triple axis_range (-1.0, 0.0, 0.8); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (0.0, 0.25, 1.0)); |
| assert (approx (out[1].first, 0.250)); |
| assert (out[1].second == Triple (0.25, 1.0, 1.0)); |
| } |
| |
| /* Case 3 boundary */ |
| { |
| Triple tent (0.0, 0.4, 1.0); |
| Triple axis_range (-1.0, 0.0, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (0.0, 0.8, 1.0)); |
| assert (approx (out[1].first, 2.5/3)); |
| assert (out[1].second == Triple (0.8, 1.0, 1.0)); |
| } |
| |
| /* Case 4 */ |
| { |
| Triple tent (0.0, 0.25, 1.0); |
| Triple axis_range (-1.0, 0.0, 0.4); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (0.0, 0.625, 1.0)); |
| assert (approx (out[1].first, 0.80)); |
| assert (out[1].second == Triple (0.625, 1.0, 1.0)); |
| } |
| |
| /* Case 4 */ |
| { |
| Triple tent (0.25, 0.3, 1.05); |
| Triple axis_range (0.0, 0.2, 0.4); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (approx (out[0].second, Triple (0.25, 0.5, 1.0))); |
| assert (approx (out[1].first, 2.6 / 3)); |
| assert (approx (out[1].second, Triple (0.5, 1.0, 1.0))); |
| } |
| |
| /* Case 4 boundary */ |
| { |
| Triple tent (0.25, 0.5, 1.0); |
| Triple axis_range (0.0, 0.25, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (0.0, 1.0, 1.0)); |
| } |
| |
| /* With gain */ |
| /* Case 3a/1neg */ |
| { |
| Triple tent (0.0, 0.5, 1.0); |
| Triple axis_range (0.0, 0.5, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 3); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == -1.0); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| assert (out[2].first == -1.0); |
| assert (out[2].second == Triple (-1.0, -1.0, 0.0)); |
| } |
| |
| { |
| Triple tent (0.0, 0.5, 1.0); |
| Triple axis_range (0.0, 0.5, 0.75); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 3); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == -0.5); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| assert (out[2].first == -1.0); |
| assert (out[2].second == Triple (-1.0, -1.0, 0.0)); |
| } |
| |
| { |
| Triple tent (0.0, 0.50, 1.0); |
| Triple axis_range (0.0, 0.25, 0.8); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 4); |
| assert (out[0].first == 0.5); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == 0.5); |
| assert (approx (out[1].second, Triple (0.0, 0.454545, 0.909091))); |
| assert (approx (out[2].first, -0.1)); |
| assert (approx (out[2].second, Triple (0.909091, 1.0, 1.0))); |
| assert (out[3].first == -0.5); |
| assert (out[3].second == Triple (-1.0, -1.0, 0.0)); |
| } |
| |
| /* Case 3a/1neg */ |
| { |
| Triple tent (0.0, 0.5, 2.0); |
| Triple axis_range (0.2, 0.5, 0.8); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 3); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (approx (out[1].first, -0.2)); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| assert (approx (out[2].first, -0.6)); |
| assert (out[2].second == Triple (-1.0, -1.0, 0.0)); |
| } |
| |
| /* Case 3a/1neg */ |
| { |
| Triple tent (0.0, 0.5, 2.0); |
| Triple axis_range (0.2, 0.5, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 3); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (approx (out[1].first, -1.0/3)); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| assert (approx (out[2].first, -0.6)); |
| assert (out[2].second == Triple (-1.0, -1.0, 0.0)); |
| } |
| |
| /* Case 3 */ |
| { |
| Triple tent (0.0, 0.5, 1.0); |
| Triple axis_range (0.25, 0.25, 0.75); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 0.5); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == 0.5); |
| assert (out[1].second == Triple (0.0, 0.5, 1.0)); |
| } |
| |
| /* Case 1neg */ |
| { |
| Triple tent (0.0, 0.5, 1.0); |
| Triple axis_range (0.0, 0.25, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 3); |
| assert (out[0].first == 0.5); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == 0.5); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| assert (out[2].first == -0.5); |
| assert (out[2].second == Triple (-1.0, -1.0, 0.0)); |
| } |
| |
| /* Case 2neg */ |
| { |
| Triple tent (0.05, 0.55, 1.0); |
| Triple axis_range (0.0, 0.25, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 4); |
| assert (approx (out[0].first, 0.4)); |
| assert (out[0].second == Triple ()); |
| assert (approx (out[1].first, 0.5)); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| assert (approx (out[2].first, -0.4)); |
| assert (out[2].second == Triple (-1.0, -0.8, 0.0)); |
| assert (approx (out[3].first, -0.4)); |
| assert (out[3].second == Triple (-1.0, -1.0, -0.8)); |
| } |
| |
| /* Case 2neg, other side */ |
| { |
| Triple tent (-1.0, -0.55, -0.05); |
| Triple axis_range (-0.5, -0.25, 0.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 4); |
| assert (approx (out[0].first, 0.4)); |
| assert (out[0].second == Triple ()); |
| assert (approx (out[1].first, 0.5)); |
| assert (out[1].second == Triple (-1.0, -1.0, 0.0)); |
| assert (approx (out[2].first, -0.4)); |
| assert (out[2].second == Triple (0.0, 0.8, 1.0)); |
| assert (approx (out[3].first, -0.4)); |
| assert (out[3].second == Triple (0.8, 1.0, 1.0)); |
| } |
| |
| /* Misc corner cases */ |
| { |
| Triple tent (0.5, 0.5, 0.5); |
| Triple axis_range (0.5, 0.5, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| } |
| |
| { |
| Triple tent (0.3, 0.5, 0.7); |
| Triple axis_range (0.1, 0.5, 0.9); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 5); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == -1.0); |
| assert (approx(out[1].second, Triple (0.0, 0.5, 1.0))); |
| assert (out[2].first == -1.0); |
| assert (approx(out[2].second, Triple (0.5, 1.0, 1.0))); |
| assert (out[3].first == -1.0); |
| assert (approx (out[3].second, Triple (-1.0, -0.5, 0.0))); |
| assert (out[4].first == -1.0); |
| assert (approx (out[4].second, Triple (-1.0, -1.0, -0.5))); |
| } |
| |
| { |
| Triple tent (0.5, 0.5, 0.5); |
| Triple axis_range (0.25, 0.25, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (1.0, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.5, 0.5, 0.5); |
| Triple axis_range (0.25, 0.35, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (1.0, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.5, 0.5, 0.55); |
| Triple axis_range (0.25, 0.35, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (1.0, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.5, 0.5, 1.0); |
| Triple axis_range (0.5, 0.5, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == -1.0); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.25, 0.5, 1.0); |
| Triple axis_range (0.5, 0.5, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == -1.0); |
| assert (out[1].second == Triple (0.0, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.0, 0.2, 1.0); |
| Triple axis_range (0.0, 0.0, 0.5); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 2); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (0.0, 0.4, 1.0)); |
| assert (out[1].first == 0.625); |
| assert (out[1].second == Triple (0.4, 1.0, 1.0)); |
| } |
| |
| |
| { |
| Triple tent (0.0, 0.5, 1.0); |
| Triple axis_range (-1.0, 0.25, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 5); |
| assert (out[0].first == 0.5); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == 0.5); |
| assert (out[1].second == Triple (0.0, 1.0/3, 2.0/3)); |
| assert (out[2].first == -0.5); |
| assert (out[2].second == Triple (2.0/3, 1.0, 1.0)); |
| assert (out[3].first == -0.5); |
| assert (out[3].second == Triple (-1.0, -0.2, 0.0)); |
| assert (out[4].first == -0.5); |
| assert (out[4].second == Triple (-1.0, -1.0, -0.2)); |
| } |
| |
| { |
| Triple tent (0.5, 0.5, 0.5); |
| Triple axis_range (0.0, 0.5, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 5); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple ()); |
| assert (out[1].first == -1.0); |
| assert (out[1].second == Triple (0.0, 2/(double) (1 << 14), 1.0)); |
| assert (out[2].first == -1.0); |
| assert (out[2].second == Triple (2/(double) (1 << 14), 1.0, 1.0)); |
| assert (out[3].first == -1.0); |
| assert (out[3].second == Triple (-1.0, -2/(double) (1 << 14), 0.0)); |
| assert (out[4].first == -1.0); |
| assert (out[4].second == Triple (-1.0, -1.0, -2/(double) (1 << 14))); |
| } |
| |
| { |
| Triple tent (0.0, 1.0, 1.0); |
| Triple axis_range (-1.0, -0.5, 1.0); |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, default_axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (1.0/3, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.0, 1.0, 1.0); |
| Triple axis_range (-1.0, -0.5, 1.0); |
| TripleDistances axis_distances{2.0, 1.0}; |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (out[0].second == Triple (0.5, 1.0, 1.0)); |
| } |
| |
| { |
| Triple tent (0.6, 0.7, 0.8); |
| Triple axis_range (-1.0, 0.2, 1.0); |
| TripleDistances axis_distances{1.0, 1.0}; |
| rebase_tent_result_t out = rebase_tent (tent, axis_range, axis_distances); |
| assert (out.length == 1); |
| assert (out[0].first == 1.0); |
| assert (approx (out[0].second, Triple (0.5, 0.625, 0.75))); |
| } |
| } |