1 /* 2 * Copyright 2018 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): Roderick Sheeter 25 */ 26 27 #include "hb-test.h" 28 #include "hb-subset-test.h" 29 30 /* Unit tests for hmtx subsetting */ 31 32 static void check_num_hmetrics(hb_face_t *face, uint16_t expected_num_hmetrics) 33 { 34 hb_blob_t *hhea_blob = hb_face_reference_table (face, HB_TAG ('h','h','e','a')); 35 hb_blob_t *hmtx_blob = hb_face_reference_table (face, HB_TAG ('h','m','t','x')); 36 37 // TODO I sure wish I could just use the hmtx table struct! 38 unsigned int hhea_len; 39 uint8_t *raw_hhea = (uint8_t *) hb_blob_get_data(hhea_blob, &hhea_len); 40 uint16_t num_hmetrics = (raw_hhea[hhea_len - 2] << 8) + raw_hhea[hhea_len - 1]; 41 g_assert_cmpuint(expected_num_hmetrics, ==, num_hmetrics); 42 43 hb_blob_destroy (hhea_blob); 44 hb_blob_destroy (hmtx_blob); 45 } 46 47 static void 48 test_subset_hmtx_simple_subset (void) 49 { 50 hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf"); 51 hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf"); 52 53 hb_set_t *codepoints = hb_set_create (); 54 hb_face_t *face_abc_subset; 55 hb_set_add (codepoints, 'a'); 56 hb_set_add (codepoints, 'c'); 57 face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); 58 hb_set_destroy (codepoints); 59 60 check_num_hmetrics(face_abc_subset, 3); /* nothing has same width */ 61 hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('h','m','t','x')); 62 63 hb_face_destroy (face_abc_subset); 64 hb_face_destroy (face_abc); 65 hb_face_destroy (face_ac); 66 } 67 68 69 static void 70 test_subset_hmtx_monospace (void) 71 { 72 hb_face_t *face_abc = hb_test_open_font_file ("fonts/Inconsolata-Regular.abc.ttf"); 73 hb_face_t *face_ac = hb_test_open_font_file ("fonts/Inconsolata-Regular.ac.ttf"); 74 75 hb_set_t *codepoints = hb_set_create (); 76 hb_face_t *face_abc_subset; 77 hb_set_add (codepoints, 'a'); 78 hb_set_add (codepoints, 'c'); 79 face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); 80 hb_set_destroy (codepoints); 81 82 check_num_hmetrics(face_abc_subset, 1); /* everything has same width */ 83 hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('h','m','t','x')); 84 85 hb_face_destroy (face_abc_subset); 86 hb_face_destroy (face_abc); 87 hb_face_destroy (face_ac); 88 } 89 90 91 static void 92 test_subset_hmtx_keep_num_metrics (void) 93 { 94 hb_face_t *face_abc = hb_test_open_font_file ("fonts/Inconsolata-Regular.abc.widerc.ttf"); 95 hb_face_t *face_ac = hb_test_open_font_file ("fonts/Inconsolata-Regular.ac.widerc.ttf"); 96 97 hb_set_t *codepoints = hb_set_create (); 98 hb_face_t *face_abc_subset; 99 hb_set_add (codepoints, 'a'); 100 hb_set_add (codepoints, 'c'); 101 face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); 102 hb_set_destroy (codepoints); 103 104 check_num_hmetrics(face_abc_subset, 3); /* c is wider */ 105 hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('h','m','t','x')); 106 107 hb_face_destroy (face_abc_subset); 108 hb_face_destroy (face_abc); 109 hb_face_destroy (face_ac); 110 } 111 112 static void 113 test_subset_hmtx_decrease_num_metrics (void) 114 { 115 hb_face_t *face_abc = hb_test_open_font_file ("fonts/Inconsolata-Regular.abc.widerc.ttf"); 116 hb_face_t *face_ab = hb_test_open_font_file ("fonts/Inconsolata-Regular.ab.ttf"); 117 118 hb_set_t *codepoints = hb_set_create (); 119 hb_face_t *face_abc_subset; 120 hb_set_add (codepoints, 'a'); 121 hb_set_add (codepoints, 'b'); 122 face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); 123 hb_set_destroy (codepoints); 124 125 check_num_hmetrics(face_abc_subset, 1); /* everything left has same width */ 126 hb_subset_test_check (face_ab, face_abc_subset, HB_TAG ('h','m','t','x')); 127 128 hb_face_destroy (face_abc_subset); 129 hb_face_destroy (face_abc); 130 hb_face_destroy (face_ab); 131 } 132 133 static void 134 test_subset_hmtx_noop (void) 135 { 136 hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf"); 137 138 hb_set_t *codepoints = hb_set_create(); 139 hb_face_t *face_abc_subset; 140 hb_set_add (codepoints, 'a'); 141 hb_set_add (codepoints, 'b'); 142 hb_set_add (codepoints, 'c'); 143 face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints)); 144 hb_set_destroy (codepoints); 145 146 check_num_hmetrics(face_abc_subset, 4); /* nothing has same width */ 147 hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('h','m','t','x')); 148 149 hb_face_destroy (face_abc_subset); 150 hb_face_destroy (face_abc); 151 } 152 153 static void 154 test_subset_invalid_hmtx (void) 155 { 156 hb_face_t *face = hb_test_open_font_file ("../fuzzing/fonts/crash-e4e0bb1458a91b692eba492c907ae1f94e635480"); 157 hb_face_t *subset; 158 159 hb_subset_input_t *input = hb_subset_input_create_or_fail (); 160 hb_set_t *codepoints = hb_subset_input_unicode_set (input); 161 hb_set_add (codepoints, 'a'); 162 hb_set_add (codepoints, 'b'); 163 hb_set_add (codepoints, 'c'); 164 165 subset = hb_subset (face, input); 166 g_assert (subset); 167 g_assert (subset == hb_face_get_empty ()); 168 169 hb_subset_input_destroy (input); 170 hb_face_destroy (subset); 171 hb_face_destroy (face); 172 } 173 174 int 175 main (int argc, char **argv) 176 { 177 hb_test_init (&argc, &argv); 178 179 hb_test_add (test_subset_hmtx_simple_subset); 180 hb_test_add (test_subset_hmtx_monospace); 181 hb_test_add (test_subset_hmtx_keep_num_metrics); 182 hb_test_add (test_subset_hmtx_decrease_num_metrics); 183 hb_test_add (test_subset_hmtx_noop); 184 hb_test_add (test_subset_invalid_hmtx); 185 186 return hb_test_run(); 187 } 188