| /* |
| * Copyright © 2025 Khaled Hosny |
| * |
| * 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. |
| * |
| */ |
| |
| #include "hb-ot.h" |
| #include "hb-test.h" |
| |
| /* Unit tests for hb-shape-plan.h */ |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_rtl (void) |
| { |
| /* Test getting features enabled for horizontal RTL text */ |
| hb_face_t *face = hb_test_open_font_file ("fonts/NotoSans-Bold.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_ARABIC; |
| props.direction = HB_DIRECTION_RTL; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, "()", -1, 0, -1); |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, NULL, 0, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, NULL, 0); |
| g_assert_true (ret); |
| |
| hb_tag_t features[16]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 16); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('a', 'b', 'v', 'm')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('d', 'i', 's', 't')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('d', 'n', 'o', 'm')); |
| g_assert_cmpint (features[4], ==, HB_TAG ('f', 'i', 'n', 'a')); |
| g_assert_cmpint (features[5], ==, HB_TAG ('f', 'r', 'a', 'c')); |
| g_assert_cmpint (features[6], ==, HB_TAG ('i', 'n', 'i', 't')); |
| g_assert_cmpint (features[7], ==, HB_TAG ('i', 's', 'o', 'l')); |
| g_assert_cmpint (features[8], ==, HB_TAG ('k', 'e', 'r', 'n')); |
| g_assert_cmpint (features[9], ==, HB_TAG ('l', 'i', 'g', 'a')); |
| g_assert_cmpint (features[10], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[11], ==, HB_TAG ('m', 'e', 'd', 'i')); |
| g_assert_cmpint (features[12], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[13], ==, HB_TAG ('n', 'u', 'm', 'r')); |
| g_assert_cmpint (features[14], ==, HB_TAG ('r', 'l', 'i', 'g')); |
| g_assert_cmpint (features[15], ==, HB_TAG ('r', 't', 'l', 'm')); |
| |
| hb_shape_plan_destroy (shape_plan); |
| hb_buffer_destroy (buffer); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_ltr (void) |
| { |
| /* Test getting features enabled for horizontal LTR text */ |
| hb_face_t *face = hb_test_open_font_file ("fonts/NotoSans-Bold.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_LATIN; |
| props.direction = HB_DIRECTION_LTR; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, NULL, 0, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, NULL, 0); |
| g_assert_true (ret); |
| |
| hb_tag_t features[10]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 10); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('a', 'b', 'v', 'm')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('d', 'i', 's', 't')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('d', 'n', 'o', 'm')); |
| g_assert_cmpint (features[4], ==, HB_TAG ('f', 'r', 'a', 'c')); |
| g_assert_cmpint (features[5], ==, HB_TAG ('k', 'e', 'r', 'n')); |
| g_assert_cmpint (features[6], ==, HB_TAG ('l', 'i', 'g', 'a')); |
| g_assert_cmpint (features[7], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[8], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[9], ==, HB_TAG ('n', 'u', 'm', 'r')); |
| |
| hb_buffer_destroy (buffer); |
| hb_shape_plan_destroy (shape_plan); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_ttb (void) |
| { |
| /* Test getting features enabled for vertical text */ |
| hb_face_t *face = hb_test_open_font_file ("fonts/Mplus1p-Regular.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_HAN; |
| props.direction = HB_DIRECTION_TTB; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, NULL, 0, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, NULL, 0); |
| g_assert_true (ret); |
| |
| hb_tag_t features[4]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 4); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('v', 'e', 'r', 't')); |
| |
| hb_buffer_destroy (buffer); |
| hb_shape_plan_destroy (shape_plan); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_userfeatures_enable (void) |
| { |
| /* test getting features enabled with user features enabling a non-default feature */ |
| hb_face_t *face = hb_test_open_font_file ("fonts/Mada-VF.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_LATIN; |
| props.direction = HB_DIRECTION_LTR; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); |
| |
| hb_feature_t user_features[1] = {{HB_TAG ('s', 's', '0', '1'), 1, 0, 1}}; |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, user_features, 1, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, user_features, 1); |
| g_assert_true (ret); |
| |
| hb_tag_t features[7]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 7); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('k', 'e', 'r', 'n')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[4], ==, HB_TAG ('r', 'c', 'l', 't')); |
| g_assert_cmpint (features[5], ==, HB_TAG ('r', 'l', 'i', 'g')); |
| g_assert_cmpint (features[6], ==, HB_TAG ('s', 's', '0', '1')); |
| |
| hb_buffer_destroy (buffer); |
| hb_shape_plan_destroy (shape_plan); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_userfeatures_disable (void) |
| { |
| /* test getting features enabled with user features disabling a default feature */ |
| hb_face_t *face = hb_test_open_font_file ("fonts/Mada-VF.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_LATIN; |
| props.direction = HB_DIRECTION_LTR; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); |
| |
| hb_feature_t user_features[1] = {{HB_TAG ('k', 'e', 'r', 'n'), 0, 0, HB_FEATURE_GLOBAL_END}}; |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, user_features, 1, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, user_features, 1); |
| g_assert_true (ret); |
| |
| hb_tag_t features[5]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 5); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('r', 'c', 'l', 't')); |
| g_assert_cmpint (features[4], ==, HB_TAG ('r', 'l', 'i', 'g')); |
| |
| hb_buffer_destroy (buffer); |
| hb_shape_plan_destroy (shape_plan); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_userfeatures_disablepartial (void) |
| { |
| /* test getting features enabled with user features disabling a non-default |
| feature partially; the tag of the disabled feature will be returned since |
| it is still enabled partially.*/ |
| hb_face_t *face = hb_test_open_font_file ("fonts/Mada-VF.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_LATIN; |
| props.direction = HB_DIRECTION_LTR; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); |
| |
| hb_feature_t user_features[1] = {{HB_TAG ('k', 'e', 'r', 'n'), 0, 0, 1}}; |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, user_features, 1, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, user_features, 1); |
| g_assert_true (ret); |
| |
| hb_tag_t features[6]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 6); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('k', 'e', 'r', 'n')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[4], ==, HB_TAG ('r', 'c', 'l', 't')); |
| g_assert_cmpint (features[5], ==, HB_TAG ('r', 'l', 'i', 'g')); |
| |
| hb_buffer_destroy (buffer); |
| hb_shape_plan_destroy (shape_plan); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| static void |
| test_ot_shape_plan_get_feature_tags_userfeatures_disablenondeafult (void) |
| { |
| /* test getting features enabled with user features disabling a non-default |
| feature; the tag of the disabled feature will be returned returned.*/ |
| hb_face_t *face = hb_test_open_font_file ("fonts/Mada-VF.ttf"); |
| hb_font_t *font = hb_font_create (face); |
| |
| hb_segment_properties_t props = HB_SEGMENT_PROPERTIES_DEFAULT; |
| props.script = HB_SCRIPT_LATIN; |
| props.direction = HB_DIRECTION_LTR; |
| |
| hb_buffer_t *buffer = hb_buffer_create (); |
| hb_buffer_set_segment_properties (buffer, &props); |
| hb_buffer_add_utf8 (buffer, " ", -1, 0, -1); |
| |
| hb_feature_t user_features[1] = {{HB_TAG ('s', 's', '0', '1'), 0, 0, HB_FEATURE_GLOBAL_END}}; |
| |
| hb_shape_plan_t *shape_plan = hb_shape_plan_create (face, &props, user_features, 1, NULL); |
| hb_bool_t ret = hb_shape_plan_execute (shape_plan, font, buffer, user_features, 1); |
| g_assert_true (ret); |
| |
| hb_tag_t features[6]; |
| unsigned int feature_count = sizeof (features) / sizeof (features[0]); |
| unsigned int count = hb_ot_shape_plan_get_feature_tags (shape_plan, 0, &feature_count, features); |
| g_assert_cmpuint (count, ==, 6); |
| g_assert_cmpuint (feature_count, ==, count); |
| |
| g_assert_cmpint (features[0], ==, HB_TAG ('c', 'c', 'm', 'p')); |
| g_assert_cmpint (features[1], ==, HB_TAG ('k', 'e', 'r', 'n')); |
| g_assert_cmpint (features[2], ==, HB_TAG ('m', 'a', 'r', 'k')); |
| g_assert_cmpint (features[3], ==, HB_TAG ('m', 'k', 'm', 'k')); |
| g_assert_cmpint (features[4], ==, HB_TAG ('r', 'c', 'l', 't')); |
| g_assert_cmpint (features[5], ==, HB_TAG ('r', 'l', 'i', 'g')); |
| |
| hb_buffer_destroy (buffer); |
| hb_shape_plan_destroy (shape_plan); |
| hb_font_destroy (font); |
| hb_face_destroy (face); |
| } |
| |
| int |
| main (int argc, char **argv) |
| { |
| hb_test_init (&argc, &argv); |
| |
| hb_test_add (test_ot_shape_plan_get_feature_tags_rtl); |
| hb_test_add (test_ot_shape_plan_get_feature_tags_ltr); |
| hb_test_add (test_ot_shape_plan_get_feature_tags_ttb); |
| hb_test_add (test_ot_shape_plan_get_feature_tags_userfeatures_enable); |
| hb_test_add (test_ot_shape_plan_get_feature_tags_userfeatures_disable); |
| hb_test_add (test_ot_shape_plan_get_feature_tags_userfeatures_disablepartial); |
| hb_test_add (test_ot_shape_plan_get_feature_tags_userfeatures_disablenondeafult); |
| |
| return hb_test_run(); |
| } |