(root)/
harfbuzz-8.3.0/
test/
api/
test-subset-glyf.c
       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): Garret Rieger
      25   */
      26  
      27  #include "hb-test.h"
      28  #include "hb-subset-test.h"
      29  
      30  /* Unit tests for hb-subset-glyf.h */
      31  
      32  static void check_maxp_field (uint8_t *raw_maxp, unsigned int offset, uint16_t expected_value)
      33  {
      34    uint16_t actual_value = (raw_maxp[offset] << 8) + raw_maxp[offset + 1];
      35    g_assert_cmpuint(expected_value, ==, actual_value);
      36  }
      37  
      38  static void check_maxp_num_glyphs (hb_face_t *face, uint16_t expected_num_glyphs, bool hints)
      39  {
      40    hb_blob_t *maxp_blob = hb_face_reference_table (face, HB_TAG ('m','a','x', 'p'));
      41  
      42    unsigned int maxp_len;
      43    uint8_t *raw_maxp = (uint8_t *) hb_blob_get_data(maxp_blob, &maxp_len);
      44  
      45    check_maxp_field (raw_maxp, 4, expected_num_glyphs); // numGlyphs
      46    if (!hints)
      47    {
      48      check_maxp_field (raw_maxp, 14, 1); // maxZones
      49      check_maxp_field (raw_maxp, 16, 0); // maxTwilightPoints
      50      check_maxp_field (raw_maxp, 18, 0); // maxStorage
      51      check_maxp_field (raw_maxp, 20, 0); // maxFunctionDefs
      52      check_maxp_field (raw_maxp, 22, 0); // maxInstructionDefs
      53      check_maxp_field (raw_maxp, 24, 0); // maxStackElements
      54      check_maxp_field (raw_maxp, 26, 0); // maxSizeOfInstructions
      55    }
      56  
      57    hb_blob_destroy (maxp_blob);
      58  }
      59  
      60  static void
      61  test_subset_glyf (void)
      62  {
      63    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
      64    hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
      65  
      66    hb_set_t *codepoints = hb_set_create();
      67    hb_face_t *face_abc_subset;
      68    hb_set_add (codepoints, 97);
      69    hb_set_add (codepoints, 99);
      70    face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
      71    hb_set_destroy (codepoints);
      72  
      73    check_maxp_num_glyphs(face_abc_subset, 3, true);
      74    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
      75    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
      76  
      77    hb_face_destroy (face_abc_subset);
      78    hb_face_destroy (face_abc);
      79    hb_face_destroy (face_ac);
      80  }
      81  
      82  static void
      83  test_subset_glyf_set_overlaps_flag (void)
      84  {
      85    hb_face_t *face_abcAE = hb_test_open_font_file ("fonts/Roboto-Regular.abcAE.ttf");
      86    hb_face_t *face_bAE = hb_test_open_font_file ("fonts/Roboto-Regular.bAE.ttf");
      87  
      88    hb_set_t *codepoints = hb_set_create();
      89    hb_face_t *face_abcAE_subset;
      90    hb_set_add (codepoints, 32);
      91    hb_set_add (codepoints, 98);
      92    hb_set_add (codepoints, 508);
      93  
      94    hb_subset_input_t* input = hb_subset_test_create_input (codepoints);
      95    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG);
      96    face_abcAE_subset = hb_subset_test_create_subset (face_abcAE, input);
      97    hb_set_destroy (codepoints);
      98  
      99    hb_subset_test_check (face_bAE, face_abcAE_subset, HB_TAG ('l','o','c', 'a'));
     100    hb_subset_test_check (face_bAE, face_abcAE_subset, HB_TAG ('g','l','y','f'));
     101  
     102    hb_face_destroy (face_abcAE_subset);
     103    hb_face_destroy (face_abcAE);
     104    hb_face_destroy (face_bAE);
     105  }
     106  
     107  static void
     108  test_subset_glyf_with_input_glyphs (void)
     109  {
     110    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
     111    hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.ttf");
     112  
     113    hb_set_t *glyphs = hb_set_create();
     114    hb_face_t *face_abc_subset;
     115    hb_set_add (glyphs, 1);
     116    hb_set_add (glyphs, 3);
     117    face_abc_subset =
     118        hb_subset_test_create_subset (face_abc, hb_subset_test_create_input_from_glyphs (glyphs));
     119    hb_set_destroy (glyphs);
     120  
     121    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
     122    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
     123    check_maxp_num_glyphs(face_abc_subset, 3, true);
     124  
     125    hb_face_destroy (face_abc_subset);
     126    hb_face_destroy (face_abc);
     127    hb_face_destroy (face_ac);
     128  }
     129  
     130  static void
     131  test_subset_glyf_with_components (void)
     132  {
     133    hb_face_t *face_components = hb_test_open_font_file ("fonts/Roboto-Regular.components.ttf");
     134    hb_face_t *face_subset = hb_test_open_font_file ("fonts/Roboto-Regular.components.subset.ttf");
     135  
     136    hb_set_t *codepoints = hb_set_create();
     137    hb_face_t *face_generated_subset;
     138    hb_set_add (codepoints, 0x1fc);
     139    face_generated_subset = hb_subset_test_create_subset (face_components, hb_subset_test_create_input (codepoints));
     140    hb_set_destroy (codepoints);
     141  
     142    hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
     143    hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
     144    check_maxp_num_glyphs(face_generated_subset, 4, true);
     145  
     146    hb_face_destroy (face_generated_subset);
     147    hb_face_destroy (face_subset);
     148    hb_face_destroy (face_components);
     149  }
     150  
     151  static void
     152  test_subset_glyf_with_gsub (void)
     153  {
     154    hb_face_t *face_fil = hb_test_open_font_file ("fonts/Roboto-Regular.gsub.fil.ttf");
     155    hb_face_t *face_fi = hb_test_open_font_file ("fonts/Roboto-Regular.gsub.fi.ttf");
     156    hb_subset_input_t *input;
     157    hb_face_t *face_subset;
     158  
     159    hb_set_t *codepoints = hb_set_create();
     160    hb_set_add (codepoints, 102); // f
     161    hb_set_add (codepoints, 105); // i
     162  
     163    input = hb_subset_test_create_input (codepoints);
     164    hb_set_destroy (codepoints);
     165    hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'S', 'U', 'B'));
     166    hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'P', 'O', 'S'));
     167    hb_set_del (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'D', 'E', 'F'));
     168  
     169    face_subset = hb_subset_test_create_subset (face_fil, input);
     170  
     171    hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f'));
     172    hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a'));
     173    check_maxp_num_glyphs(face_subset, 5, true);
     174  
     175    hb_face_destroy (face_subset);
     176    hb_face_destroy (face_fi);
     177    hb_face_destroy (face_fil);
     178  }
     179  
     180  static void
     181  test_subset_glyf_without_gsub (void)
     182  {
     183    hb_face_t *face_fil = hb_test_open_font_file ("fonts/Roboto-Regular.gsub.fil.ttf");
     184    hb_face_t *face_fi = hb_test_open_font_file ("fonts/Roboto-Regular.nogsub.fi.ttf");
     185    hb_subset_input_t *input;
     186    hb_face_t *face_subset;
     187  
     188    hb_set_t *codepoints = hb_set_create();
     189    hb_set_add (codepoints, 102); // f
     190    hb_set_add (codepoints, 105); // i
     191  
     192    input = hb_subset_test_create_input (codepoints);
     193    hb_set_destroy (codepoints);
     194    hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'S', 'U', 'B'));
     195    hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'P', 'O', 'S'));
     196    hb_set_add (hb_subset_input_set (input, HB_SUBSET_SETS_DROP_TABLE_TAG), HB_TAG('G', 'D', 'E', 'F'));
     197  
     198    face_subset = hb_subset_test_create_subset (face_fil, input);
     199  
     200    hb_subset_test_check (face_fi, face_subset, HB_TAG ('g','l','y','f'));
     201    hb_subset_test_check (face_fi, face_subset, HB_TAG ('l','o','c', 'a'));
     202    check_maxp_num_glyphs(face_subset, 3, true);
     203  
     204    hb_face_destroy (face_subset);
     205    hb_face_destroy (face_fi);
     206    hb_face_destroy (face_fil);
     207  }
     208  
     209  static void
     210  test_subset_glyf_noop (void)
     211  {
     212    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
     213  
     214    hb_set_t *codepoints = hb_set_create();
     215    hb_face_t *face_abc_subset;
     216    hb_set_add (codepoints, 97);
     217    hb_set_add (codepoints, 98);
     218    hb_set_add (codepoints, 99);
     219    face_abc_subset = hb_subset_test_create_subset (face_abc, hb_subset_test_create_input (codepoints));
     220    hb_set_destroy (codepoints);
     221  
     222    check_maxp_num_glyphs(face_abc_subset, 4, true);
     223    hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('l','o','c', 'a'));
     224    hb_subset_test_check (face_abc, face_abc_subset, HB_TAG ('g','l','y','f'));
     225  
     226    hb_face_destroy (face_abc_subset);
     227    hb_face_destroy (face_abc);
     228  }
     229  
     230  static void
     231  test_subset_glyf_strip_hints_simple (void)
     232  {
     233    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
     234    hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.nohints.ttf");
     235  
     236    hb_set_t *codepoints = hb_set_create();
     237    hb_subset_input_t *input;
     238    hb_face_t *face_abc_subset;
     239    hb_set_add (codepoints, 'a');
     240    hb_set_add (codepoints, 'c');
     241    input = hb_subset_test_create_input (codepoints);
     242    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
     243    face_abc_subset = hb_subset_test_create_subset (face_abc, input);
     244    hb_set_destroy (codepoints);
     245  
     246    check_maxp_num_glyphs(face_abc_subset, 3, false);
     247    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
     248    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
     249  
     250    hb_face_destroy (face_abc_subset);
     251    hb_face_destroy (face_abc);
     252    hb_face_destroy (face_ac);
     253  }
     254  
     255  static void
     256  test_subset_glyf_strip_hints_composite (void)
     257  {
     258    hb_face_t *face_components = hb_test_open_font_file ("fonts/Roboto-Regular.components.ttf");
     259    hb_face_t *face_subset = hb_test_open_font_file ("fonts/Roboto-Regular.components.1fc.nohints.ttf");
     260  
     261    hb_set_t *codepoints = hb_set_create();
     262    hb_subset_input_t *input;
     263    hb_face_t *face_generated_subset;
     264    hb_set_add (codepoints, 0x1fc);
     265    input = hb_subset_test_create_input (codepoints);
     266    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
     267  
     268    face_generated_subset = hb_subset_test_create_subset (face_components, input);
     269    hb_set_destroy (codepoints);
     270  
     271    check_maxp_num_glyphs(face_generated_subset, 4, false);
     272    hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('l','o','c', 'a'));
     273    hb_subset_test_check (face_subset, face_generated_subset, HB_TAG ('g','l','y','f'));
     274  
     275    hb_face_destroy (face_generated_subset);
     276    hb_face_destroy (face_subset);
     277    hb_face_destroy (face_components);
     278  }
     279  
     280  static void
     281  test_subset_glyf_strip_hints_invalid (void)
     282  {
     283    hb_face_t *face = hb_test_open_font_file ("../fuzzing/fonts/oom-ccc61c92d589f895174cdef6ff2e3b20e9999a1a");
     284  
     285    hb_set_t *codepoints = hb_set_create();
     286    const hb_codepoint_t text[] =
     287    {
     288      'A', 'B', 'C', 'D', 'E', 'X', 'Y', 'Z', '1', '2',
     289      '3', '@', '_', '%', '&', ')', '*', '$', '!'
     290    };
     291    unsigned int i;
     292    hb_subset_input_t *input;
     293    hb_face_t *face_subset;
     294  
     295    for (i = 0; i < sizeof (text) / sizeof (hb_codepoint_t); i++)
     296    {
     297      hb_set_add (codepoints, text[i]);
     298    }
     299  
     300    input = hb_subset_test_create_input (codepoints);
     301    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_NO_HINTING);
     302    hb_set_destroy (codepoints);
     303  
     304    face_subset = hb_subset_or_fail (face, input);
     305    g_assert (!face_subset);
     306  
     307    hb_subset_input_destroy (input);
     308    hb_face_destroy (face);
     309  }
     310  
     311  static void
     312  test_subset_glyf_retain_gids (void)
     313  {
     314    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
     315    hb_face_t *face_ac = hb_test_open_font_file ("fonts/Roboto-Regular.ac.retaingids.ttf");
     316  
     317    hb_set_t *codepoints = hb_set_create();
     318    hb_face_t *face_abc_subset;
     319    hb_set_add (codepoints, 97);
     320    hb_set_add (codepoints, 99);
     321  
     322    hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
     323    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
     324    face_abc_subset = hb_subset_test_create_subset (face_abc, input);
     325    hb_set_destroy (codepoints);
     326  
     327    check_maxp_num_glyphs(face_abc_subset, 4, true);
     328    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('l','o','c', 'a'));
     329    hb_subset_test_check (face_ac, face_abc_subset, HB_TAG ('g','l','y','f'));
     330  
     331    hb_face_destroy (face_abc_subset);
     332    hb_face_destroy (face_abc);
     333    hb_face_destroy (face_ac);
     334  }
     335  
     336  static void
     337  test_subset_glyf_retain_gids_truncates (void)
     338  {
     339    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Regular.abc.ttf");
     340    hb_face_t *face_a = hb_test_open_font_file ("fonts/Roboto-Regular.a.retaingids.ttf");
     341  
     342    hb_set_t *codepoints = hb_set_create();
     343    hb_face_t *face_abc_subset;
     344    hb_set_add (codepoints, 97);
     345  
     346    hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
     347    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_RETAIN_GIDS);
     348    face_abc_subset = hb_subset_test_create_subset (face_abc, input);
     349    hb_set_destroy (codepoints);
     350  
     351    check_maxp_num_glyphs(face_abc_subset, 2, true);
     352    hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('l','o','c', 'a'));
     353    hb_subset_test_check (face_a, face_abc_subset, HB_TAG ('g','l','y','f'));
     354  
     355    hb_face_destroy (face_abc_subset);
     356    hb_face_destroy (face_abc);
     357    hb_face_destroy (face_a);
     358  }
     359  
     360  #ifdef HB_EXPERIMENTAL_API
     361  static void
     362  test_subset_glyf_iftb_requirements (void)
     363  {
     364    hb_face_t *face_abc = hb_test_open_font_file ("fonts/Roboto-Variable.abc.ttf");
     365    hb_face_t *face_long_loca = hb_test_open_font_file ("fonts/Roboto-Variable.abc.long_loca.ttf");
     366  
     367    hb_set_t *codepoints = hb_set_create();
     368    hb_face_t *face_abc_subset;
     369    hb_set_add (codepoints, 97);
     370    hb_set_add (codepoints, 98);
     371    hb_set_add (codepoints, 99);
     372  
     373    hb_subset_input_t *input = hb_subset_test_create_input (codepoints);
     374    hb_subset_input_set_flags (input, HB_SUBSET_FLAGS_IFTB_REQUIREMENTS);
     375    face_abc_subset = hb_subset_test_create_subset (face_abc, input);
     376    hb_set_destroy (codepoints);
     377  
     378    hb_subset_test_check (face_long_loca, face_abc_subset, HB_TAG ('l','o','c', 'a'));
     379    hb_subset_test_check (face_long_loca, face_abc_subset, HB_TAG ('g','l','y','f'));
     380    hb_subset_test_check (face_long_loca, face_abc_subset, HB_TAG ('g','v','a','r'));
     381  
     382    hb_face_destroy (face_abc_subset);
     383    hb_face_destroy (face_abc);
     384    hb_face_destroy (face_long_loca);
     385  
     386  }
     387  #endif
     388  
     389  // TODO(grieger): test for long loca generation.
     390  
     391  int
     392  main (int argc, char **argv)
     393  {
     394    hb_test_init (&argc, &argv);
     395  
     396    hb_test_add (test_subset_glyf_noop);
     397    hb_test_add (test_subset_glyf);
     398    hb_test_add (test_subset_glyf_set_overlaps_flag);
     399    hb_test_add (test_subset_glyf_with_input_glyphs);
     400    hb_test_add (test_subset_glyf_strip_hints_simple);
     401    hb_test_add (test_subset_glyf_strip_hints_composite);
     402    hb_test_add (test_subset_glyf_strip_hints_invalid);
     403    hb_test_add (test_subset_glyf_with_components);
     404    hb_test_add (test_subset_glyf_with_gsub);
     405    hb_test_add (test_subset_glyf_without_gsub);
     406    hb_test_add (test_subset_glyf_retain_gids);
     407    hb_test_add (test_subset_glyf_retain_gids_truncates);
     408  
     409  #ifdef HB_EXPERIMENTAL_API
     410    hb_test_add (test_subset_glyf_iftb_requirements);
     411  #endif
     412  
     413    return hb_test_run();
     414  }