TODO | 2 src/hb-atomic-private.hh | 2 src/hb-ot-layout-gsubgpos-private.hh | 19 ++ src/hb-ot-layout.cc | 123 +++++++++++++++--- src/hb-set-private.hh | 19 ++ src/hb-set.cc | 9 + src/hb-set.h | 3 test/api/Makefile.am | 1 test/api/test-object.c | 12 + test/api/test-set.c | 237 +++++++++++++++++++++++++++++++++++ 10 files changed, 401 insertions(+), 26 deletions(-)
New commits: commit f0c82410dbe800cb6429ba4aa7cfd9f5a11cc70c Author: Behdad Esfahbod <[email protected]> Date: Thu Jan 3 00:07:16 2013 -0600 [OTLayout] Always collect default language system in collect_lookups Not sure if this is the most desired behavior. It's the most easily defined though. diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 4a86b6b..5c266e6 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -496,6 +496,13 @@ _hb_ot_layout_collect_lookups_languages (hb_face_t *face, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */) { + _hb_ot_layout_collect_lookups_features (face, + table_tag, + script_index, + HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX, + features, + lookup_indexes); + if (!languages) { /* All languages */ commit 15e9e4e1ddaad655988144e7a56a765e8adf8782 Author: Behdad Esfahbod <[email protected]> Date: Thu Jan 3 00:04:40 2013 -0600 [OTLayout] Fix feature iteration in collect_lookups Previous logic was just wrong. diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 56c0a19..4a86b6b 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -447,17 +447,30 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face, if (!features) { /* All features */ - unsigned int count = hb_ot_layout_language_get_feature_tags (face, - table_tag, - script_index, - language_index, - 0, NULL, NULL); - for (unsigned int feature_index = 0; feature_index < count; feature_index++) - _hb_ot_layout_collect_lookups_lookups (face, - table_tag, - feature_index, - lookup_indexes); - } else { + unsigned int feature_indices[32]; + unsigned int offset, len; + + offset = 0; + do { + len = ARRAY_LENGTH (feature_indices); + hb_ot_layout_language_get_feature_indexes (face, + table_tag, + script_index, + language_index, + offset, &len, + feature_indices); + + for (unsigned int i = 0; i < len; i++) + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + feature_indices[i], + lookup_indexes); + + offset += len; + } while (len == ARRAY_LENGTH (feature_indices)); + } + else + { for (; *features; features++) { unsigned int feature_index; @@ -497,7 +510,9 @@ _hb_ot_layout_collect_lookups_languages (hb_face_t *face, language_index, features, lookup_indexes); - } else { + } + else + { for (; *languages; languages++) { unsigned int language_index; @@ -537,7 +552,9 @@ hb_ot_layout_collect_lookups (hb_face_t *face, languages, features, lookup_indexes); - } else { + } + else + { for (; *scripts; scripts++) { unsigned int script_index; @@ -572,7 +589,8 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, glyphs_after, glyphs_output); - switch (table_tag) { + switch (table_tag) + { case HB_OT_TAG_GSUB: { const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index); commit 733e8c0d7bf0765884f2cc953c8edcd7ab7fb49b Author: Behdad Esfahbod <[email protected]> Date: Thu Jan 3 00:00:23 2013 -0600 [OTLayout] Whitespace diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index 8edb135..56c0a19 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -439,20 +439,38 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face, script_index, language_index, &required_feature_index)) - _hb_ot_layout_collect_lookups_lookups (face, table_tag, required_feature_index, lookup_indexes); + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + required_feature_index, + lookup_indexes); if (!features) { /* All features */ - unsigned int count = hb_ot_layout_language_get_feature_tags (face, table_tag, script_index, language_index, 0, NULL, NULL); + unsigned int count = hb_ot_layout_language_get_feature_tags (face, + table_tag, + script_index, + language_index, + 0, NULL, NULL); for (unsigned int feature_index = 0; feature_index < count; feature_index++) - _hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes); + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + feature_index, + lookup_indexes); } else { for (; *features; features++) { unsigned int feature_index; - if (hb_ot_layout_language_find_feature (face, table_tag, script_index, language_index, *features, &feature_index)) - _hb_ot_layout_collect_lookups_lookups (face, table_tag, feature_index, lookup_indexes); + if (hb_ot_layout_language_find_feature (face, + table_tag, + script_index, + language_index, + *features, + &feature_index)) + _hb_ot_layout_collect_lookups_lookups (face, + table_tag, + feature_index, + lookup_indexes); } } } @@ -468,15 +486,32 @@ _hb_ot_layout_collect_lookups_languages (hb_face_t *face, if (!languages) { /* All languages */ - unsigned int count = hb_ot_layout_script_get_language_tags (face, table_tag, script_index, 0, NULL, NULL); + unsigned int count = hb_ot_layout_script_get_language_tags (face, + table_tag, + script_index, + 0, NULL, NULL); for (unsigned int language_index = 0; language_index < count; language_index++) - _hb_ot_layout_collect_lookups_features (face, table_tag, script_index, language_index, features, lookup_indexes); + _hb_ot_layout_collect_lookups_features (face, + table_tag, + script_index, + language_index, + features, + lookup_indexes); } else { for (; *languages; languages++) { unsigned int language_index; - if (hb_ot_layout_script_find_language (face, table_tag, script_index, *languages, &language_index)) - _hb_ot_layout_collect_lookups_features (face, table_tag, script_index, language_index, features, lookup_indexes); + if (hb_ot_layout_script_find_language (face, + table_tag, + script_index, + *languages, + &language_index)) + _hb_ot_layout_collect_lookups_features (face, + table_tag, + script_index, + language_index, + features, + lookup_indexes); } } } @@ -492,15 +527,30 @@ hb_ot_layout_collect_lookups (hb_face_t *face, if (!scripts) { /* All scripts */ - unsigned int count = hb_ot_layout_table_get_script_tags (face, table_tag, 0, NULL, NULL); + unsigned int count = hb_ot_layout_table_get_script_tags (face, + table_tag, + 0, NULL, NULL); for (unsigned int script_index = 0; script_index < count; script_index++) - _hb_ot_layout_collect_lookups_languages (face, table_tag, script_index, languages, features, lookup_indexes); + _hb_ot_layout_collect_lookups_languages (face, + table_tag, + script_index, + languages, + features, + lookup_indexes); } else { for (; *scripts; scripts++) { unsigned int script_index; - if (hb_ot_layout_table_find_script (face, table_tag, *scripts, &script_index)) - _hb_ot_layout_collect_lookups_languages (face, table_tag, script_index, languages, features, lookup_indexes); + if (hb_ot_layout_table_find_script (face, + table_tag, + *scripts, + &script_index)) + _hb_ot_layout_collect_lookups_languages (face, + table_tag, + script_index, + languages, + features, + lookup_indexes); } } } @@ -516,7 +566,11 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t *face, { if (unlikely (!hb_ot_shaper_face_data_ensure (face))) return; - OT::hb_collect_glyphs_context_t c (face, glyphs_before, glyphs_input, glyphs_after, glyphs_output); + OT::hb_collect_glyphs_context_t c (face, + glyphs_before, + glyphs_input, + glyphs_after, + glyphs_output); switch (table_tag) { case HB_OT_TAG_GSUB: commit d37ae38047bee12639741af9bb083b857fab950d Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 23:57:36 2013 -0600 [OTLayout] Handle required_feature_index in collect_lookups diff --git a/src/hb-ot-layout.cc b/src/hb-ot-layout.cc index e4bac0a..8edb135 100644 --- a/src/hb-ot-layout.cc +++ b/src/hb-ot-layout.cc @@ -433,6 +433,14 @@ _hb_ot_layout_collect_lookups_features (hb_face_t *face, const hb_tag_t *features, hb_set_t *lookup_indexes /* OUT */) { + unsigned int required_feature_index; + if (hb_ot_layout_language_get_required_feature_index (face, + table_tag, + script_index, + language_index, + &required_feature_index)) + _hb_ot_layout_collect_lookups_lookups (face, table_tag, required_feature_index, lookup_indexes); + if (!features) { /* All features */ commit 11fba79ee9383eb995ddf7eb924dd64c67e2df63 Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 23:36:37 2013 -0600 [OTLayout] Fix various introspection issues with ClassDef's As reported by Jonathan Kew. diff --git a/src/hb-ot-layout-gsubgpos-private.hh b/src/hb-ot-layout-gsubgpos-private.hh index 87abd3b..40be861 100644 --- a/src/hb-ot-layout-gsubgpos-private.hh +++ b/src/hb-ot-layout-gsubgpos-private.hh @@ -1175,7 +1175,7 @@ struct ContextFormat2 struct ContextClosureLookupContext lookup_context = { {intersects_class}, - NULL + &class_def }; unsigned int count = ruleSet.len; @@ -1191,9 +1191,10 @@ struct ContextFormat2 TRACE_COLLECT_GLYPHS (this); (this+coverage).add_coverage (c->input); + const ClassDef &class_def = this+classDef; struct ContextCollectGlyphsLookupContext lookup_context = { {collect_class}, - NULL + &class_def }; unsigned int count = ruleSet.len; @@ -1750,9 +1751,15 @@ struct ChainContextFormat2 TRACE_COLLECT_GLYPHS (this); (this+coverage).add_coverage (c->input); + const ClassDef &backtrack_class_def = this+backtrackClassDef; + const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; + struct ChainContextCollectGlyphsLookupContext lookup_context = { {collect_class}, - {NULL, NULL, NULL} + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} }; unsigned int count = ruleSet.len; @@ -1764,13 +1771,17 @@ struct ChainContextFormat2 { TRACE_WOULD_APPLY (this); + const ClassDef &backtrack_class_def = this+backtrackClassDef; const ClassDef &input_class_def = this+inputClassDef; + const ClassDef &lookahead_class_def = this+lookaheadClassDef; unsigned int index = input_class_def.get_class (c->glyphs[0]); const ChainRuleSet &rule_set = this+ruleSet[index]; struct ChainContextApplyLookupContext lookup_context = { {match_class}, - {NULL, &input_class_def, NULL} + {&backtrack_class_def, + &input_class_def, + &lookahead_class_def} }; return TRACE_RETURN (rule_set.would_apply (c, lookup_context)); } commit e81aff9ef785be28751aab1fcd484af550656181 Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 23:22:54 2013 -0600 [tests] Finish test-set.c All passing now. diff --git a/test/api/test-set.c b/test/api/test-set.c index f59760d..b9e7ef8 100644 --- a/test/api/test-set.c +++ b/test/api/test-set.c @@ -29,243 +29,169 @@ /* Unit tests for hb-set.h */ -#if 0 static void -test_buffer_properties (fixture_t *fixture, gconstpointer user_data) +test_empty (hb_set_t *s) { - hb_buffer_t *b = fixture->buffer; - hb_unicode_funcs_t *ufuncs; - - /* test default properties */ - - g_assert (hb_buffer_get_unicode_funcs (b) == hb_unicode_funcs_get_default ()); - g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID); - g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID); - g_assert (hb_buffer_get_language (b) == NULL); - g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT); - - - /* test property changes are retained */ - ufuncs = hb_unicode_funcs_create (NULL); - hb_buffer_set_unicode_funcs (b, ufuncs); - hb_unicode_funcs_destroy (ufuncs); - g_assert (hb_buffer_get_unicode_funcs (b) == ufuncs); - - hb_buffer_set_direction (b, HB_DIRECTION_RTL); - g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_RTL); - - hb_buffer_set_script (b, HB_SCRIPT_ARABIC); - g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC); - - hb_buffer_set_language (b, hb_language_from_string ("fa", -1)); - g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1)); - - hb_buffer_set_flags (b, HB_BUFFER_FLAG_BOT); - g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAG_BOT); - - - - /* test clear clears all properties but unicode_funcs */ - - hb_buffer_clear (b); - - g_assert (hb_buffer_get_unicode_funcs (b) == ufuncs); - g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID); - g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID); - g_assert (hb_buffer_get_language (b) == NULL); - g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT); - - - /* test reset clears all properties */ - - hb_buffer_set_direction (b, HB_DIRECTION_RTL); - g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_RTL); - - hb_buffer_set_script (b, HB_SCRIPT_ARABIC); - g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC); - - hb_buffer_set_language (b, hb_language_from_string ("fa", -1)); - g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1)); - - hb_buffer_set_flags (b, HB_BUFFER_FLAG_BOT); - g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAG_BOT); - - hb_buffer_reset (b); - - g_assert (hb_buffer_get_unicode_funcs (b) == hb_unicode_funcs_get_default ()); - g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID); - g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID); - g_assert (hb_buffer_get_language (b) == NULL); - g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT); + hb_codepoint_t next = (hb_codepoint_t) -1; + g_assert_cmpint (hb_set_get_population (s), ==, 0); + g_assert_cmpint (hb_set_get_min (s), ==, (hb_codepoint_t) -1); + g_assert_cmpint (hb_set_get_max (s), ==, (hb_codepoint_t) -1); + g_assert (!hb_set_has (s, 13)); + g_assert (!hb_set_next (s, &next)); + g_assert_cmpint (next, ==, (hb_codepoint_t) -1); } static void -test_buffer_contents (fixture_t *fixture, gconstpointer user_data) +test_not_empty (hb_set_t *s) { - hb_buffer_t *b = fixture->buffer; - unsigned int i, len, len2; - buffer_type_t buffer_type = GPOINTER_TO_INT (user_data); - hb_glyph_info_t *glyphs; - - if (buffer_type == BUFFER_EMPTY) { - g_assert_cmpint (hb_buffer_get_population (b), ==, 0); - return; - } - - len = hb_buffer_get_population (b); - hb_buffer_get_glyph_infos (b, NULL); /* test NULL */ - glyphs = hb_buffer_get_glyph_infos (b, &len2); - g_assert_cmpint (len, ==, len2); - g_assert_cmpint (len, ==, 5); - - for (i = 0; i < len; i++) { - g_assert_cmphex (glyphs[i].mask, ==, 1); - g_assert_cmphex (glyphs[i].var1.u32, ==, 0); - g_assert_cmphex (glyphs[i].var2.u32, ==, 0); - } - - for (i = 0; i < len; i++) { - unsigned int cluster; - cluster = 1+i; - if (i >= 2) { - if (buffer_type == BUFFER_UTF16) - cluster++; - else if (buffer_type == BUFFER_UTF8) - cluster += 3; - } - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - g_assert_cmphex (glyphs[i].cluster, ==, cluster); - } - - /* reverse, test, and reverse back */ - - hb_buffer_reverse (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]); - - hb_buffer_reverse (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - - /* reverse_clusters works same as reverse for now since each codepoint is - * in its own cluster */ - - hb_buffer_reverse_clusters (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]); - - hb_buffer_reverse_clusters (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - - /* now form a cluster and test again */ - glyphs[2].cluster = glyphs[1].cluster; - - /* reverse, test, and reverse back */ - - hb_buffer_reverse (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]); - - hb_buffer_reverse (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - - /* reverse_clusters twice still should return the original string, - * but when applied once, the 1-2 cluster should be retained. */ - - hb_buffer_reverse_clusters (b); - for (i = 0; i < len; i++) { - unsigned int j = len-1-i; - if (j == 1) - j = 2; - else if (j == 2) - j = 1; - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+j]); - } - - hb_buffer_reverse_clusters (b); - for (i = 0; i < len; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - - - /* test setting length */ - - /* enlarge */ - g_assert (hb_buffer_set_length (b, 10)); - glyphs = hb_buffer_get_glyph_infos (b, NULL); - g_assert_cmpint (hb_buffer_get_population (b), ==, 10); - for (i = 0; i < 5; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - for (i = 5; i < 10; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, 0); - /* shrink */ - g_assert (hb_buffer_set_length (b, 3)); - glyphs = hb_buffer_get_glyph_infos (b, NULL); - g_assert_cmpint (hb_buffer_get_population (b), ==, 3); - for (i = 0; i < 3; i++) - g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); - - - g_assert (hb_buffer_allocation_successful (b)); - - - /* test reset clears content */ - - hb_buffer_reset (b); - g_assert_cmpint (hb_buffer_get_population (b), ==, 0); + hb_codepoint_t next = (hb_codepoint_t) -1; + g_assert_cmpint (hb_set_get_population (s), !=, 0); + g_assert_cmpint (hb_set_get_min (s), !=, (hb_codepoint_t) -1); + g_assert_cmpint (hb_set_get_max (s), !=, (hb_codepoint_t) -1); + g_assert (hb_set_next (s, &next)); + g_assert_cmpint (next, !=, (hb_codepoint_t) -1); } static void -test_buffer_allocation (fixture_t *fixture, gconstpointer user_data) +test_set_basic (void) { - hb_buffer_t *b = fixture->buffer; - - g_assert_cmpint (hb_buffer_get_population (b), ==, 0); - - g_assert (hb_buffer_pre_allocate (b, 100)); - g_assert_cmpint (hb_buffer_get_population (b), ==, 0); - g_assert (hb_buffer_allocation_successful (b)); - - /* lets try a huge allocation, make sure it fails */ - g_assert (!hb_buffer_pre_allocate (b, (unsigned int) -1)); - g_assert_cmpint (hb_buffer_get_population (b), ==, 0); - g_assert (!hb_buffer_allocation_successful (b)); - - /* small one again */ - g_assert (hb_buffer_pre_allocate (b, 50)); - g_assert_cmpint (hb_buffer_get_population (b), ==, 0); - g_assert (!hb_buffer_allocation_successful (b)); - - hb_buffer_reset (b); - g_assert (hb_buffer_allocation_successful (b)); - - /* all allocation and size */ - g_assert (!hb_buffer_pre_allocate (b, ((unsigned int) -1) / 20 + 1)); - g_assert (!hb_buffer_allocation_successful (b)); - - hb_buffer_reset (b); - g_assert (hb_buffer_allocation_successful (b)); - - /* technically, this one can actually pass on 64bit machines, but - * I'm doubtful that any malloc allows 4GB allocations at a time. - * But let's only enable it on a 32-bit machine. */ - if (sizeof (long) == 4) { - g_assert (!hb_buffer_pre_allocate (b, ((unsigned int) -1) / 20 - 1)); - g_assert (!hb_buffer_allocation_successful (b)); - } + hb_set_t *s = hb_set_create (); + + test_empty (s); + hb_set_add (s, 13); + test_not_empty (s); + + hb_set_clear (s); + test_empty (s); + + hb_set_add_range (s, 10, 29); + test_not_empty (s); + g_assert (hb_set_has (s, 13)); + g_assert_cmpint (hb_set_get_population (s), ==, 20); + g_assert_cmpint (hb_set_get_min (s), ==, 10); + g_assert_cmpint (hb_set_get_max (s), ==, 29); + + hb_set_invert (s); + test_not_empty (s); + g_assert (!hb_set_has (s, 13)); + g_assert_cmpint (hb_set_get_min (s), ==, 0); + + hb_set_invert (s); + test_not_empty (s); + g_assert (hb_set_has (s, 13)); + g_assert_cmpint (hb_set_get_population (s), ==, 20); + g_assert_cmpint (hb_set_get_min (s), ==, 10); + g_assert_cmpint (hb_set_get_max (s), ==, 29); + + hb_set_del_range (s, 10, 18); + test_not_empty (s); + g_assert (!hb_set_has (s, 13)); +} - hb_buffer_reset (b); - g_assert (hb_buffer_allocation_successful (b)); +static void +test_set_algebra (void) +{ + hb_set_t *s = hb_set_create (); + hb_set_t *o = hb_set_create (); + + hb_set_add (o, 13); + hb_set_add (o, 19); + + test_empty (s); + g_assert (!hb_set_is_equal (s, o)); + hb_set_set (s, o); + g_assert (hb_set_is_equal (s, o)); + test_not_empty (s); + g_assert_cmpint (hb_set_get_population (s), ==, 2); + + hb_set_clear (s); + test_empty (s); + hb_set_add (s, 10); + g_assert_cmpint (hb_set_get_population (s), ==, 1); + hb_set_union (s, o); + g_assert_cmpint (hb_set_get_population (s), ==, 3); + g_assert (hb_set_has (s, 10)); + g_assert (hb_set_has (s, 13)); + + hb_set_clear (s); + test_empty (s); + hb_set_add_range (s, 10, 17); + g_assert (!hb_set_is_equal (s, o)); + hb_set_intersect (s, o); + g_assert (!hb_set_is_equal (s, o)); + test_not_empty (s); + g_assert_cmpint (hb_set_get_population (s), ==, 1); + g_assert (!hb_set_has (s, 10)); + g_assert (hb_set_has (s, 13)); + + hb_set_clear (s); + test_empty (s); + hb_set_add_range (s, 10, 17); + g_assert (!hb_set_is_equal (s, o)); + hb_set_subtract (s, o); + g_assert (!hb_set_is_equal (s, o)); + test_not_empty (s); + g_assert_cmpint (hb_set_get_population (s), ==, 7); + g_assert (hb_set_has (s, 12)); + g_assert (!hb_set_has (s, 13)); + g_assert (!hb_set_has (s, 19)); + + hb_set_clear (s); + test_empty (s); + hb_set_add_range (s, 10, 17); + g_assert (!hb_set_is_equal (s, o)); + hb_set_symmetric_difference (s, o); + g_assert (!hb_set_is_equal (s, o)); + test_not_empty (s); + g_assert_cmpint (hb_set_get_population (s), ==, 8); + g_assert (hb_set_has (s, 12)); + g_assert (!hb_set_has (s, 13)); + g_assert (hb_set_has (s, 19)); } -#endif static void -test_empty (hb_set_t *b) +test_set_iter (void) { - g_assert_cmpint (hb_set_get_population (b), ==, 0); - g_assert_cmpint (hb_set_get_min (b), ==, (hb_codepoint_t) -1); - g_assert_cmpint (hb_set_get_max (b), ==, (hb_codepoint_t) -1); + hb_codepoint_t next, first, last; + hb_set_t *s = hb_set_create (); + + hb_set_add (s, 13); + hb_set_add_range (s, 6, 6); + hb_set_add_range (s, 10, 15); + hb_set_add (s, 20005); + + test_not_empty (s); + + next = (hb_codepoint_t) -1; + g_assert (hb_set_next (s, &next)); + g_assert_cmpint (next, ==, 6); + g_assert (hb_set_next (s, &next)); + g_assert_cmpint (next, ==, 10); + g_assert (hb_set_next (s, &next)); + g_assert (hb_set_next (s, &next)); + g_assert (hb_set_next (s, &next)); + g_assert_cmpint (next, ==, 13); + g_assert (hb_set_next (s, &next)); + g_assert (hb_set_next (s, &next)); + g_assert_cmpint (next, ==, 15); + g_assert (hb_set_next (s, &next)); + g_assert_cmpint (next, ==, 20005); + g_assert (!hb_set_next (s, &next)); + g_assert_cmpint (next, ==, 20005); + + first = last = (hb_codepoint_t) -1; + g_assert (hb_set_next_range (s, &first, &last)); + g_assert_cmpint (first, ==, 6); + g_assert_cmpint (last, ==, 6); + g_assert (hb_set_next_range (s, &first, &last)); + g_assert_cmpint (first, ==, 10); + g_assert_cmpint (last, ==, 15); + g_assert (hb_set_next_range (s, &first, &last)); + g_assert_cmpint (first, ==, 20005); + g_assert_cmpint (last, ==, 20005); + g_assert (!hb_set_next_range (s, &first, &last)); + g_assert_cmpint (first, ==, 20005); + g_assert_cmpint (last, ==, 20005); } static void @@ -302,10 +228,9 @@ main (int argc, char **argv) { hb_test_init (&argc, &argv); -#if 0 + hb_test_add (test_set_basic); hb_test_add (test_set_algebra); hb_test_add (test_set_iter); -#endif hb_test_add (test_set_empty); return hb_test_run(); commit 7b1b720a8da69b68b775ce17104a40d55401b7ef Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 23:02:59 2013 -0600 Protect sets in-error from further modication Fixes test-set.c diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index 8e03d68..5e30a7e 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set-private.hh @@ -146,6 +146,9 @@ struct hb_set_t inline void fini (void) { } inline void clear (void) { + if (unlikely (hb_object_is_inert (this))) + return; + in_error = false; memset (elts, 0, sizeof elts); } inline bool is_empty (void) const { @@ -156,23 +159,27 @@ struct hb_set_t } inline void add (hb_codepoint_t g) { + if (unlikely (in_error)) return; if (unlikely (g == SENTINEL)) return; if (unlikely (g > MAX_G)) return; elt (g) |= mask (g); } inline void add_range (hb_codepoint_t a, hb_codepoint_t b) { + if (unlikely (in_error)) return; /* TODO Speedup */ for (unsigned int i = a; i < b + 1; i++) add (i); } inline void del (hb_codepoint_t g) { + if (unlikely (in_error)) return; if (unlikely (g > MAX_G)) return; elt (g) &= ~mask (g); } inline void del_range (hb_codepoint_t a, hb_codepoint_t b) { + if (unlikely (in_error)) return; /* TODO Speedup */ for (unsigned int i = a; i < b + 1; i++) del (i); @@ -202,31 +209,37 @@ struct hb_set_t } inline void set (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] = other->elts[i]; } inline void union_ (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] |= other->elts[i]; } inline void intersect (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] &= other->elts[i]; } inline void subtract (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] &= ~other->elts[i]; } inline void symmetric_difference (const hb_set_t *other) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] ^= other->elts[i]; } inline void invert (void) { + if (unlikely (in_error)) return; for (unsigned int i = 0; i < ELTS; i++) elts[i] = ~elts[i]; } commit 8165f2765b93e99577ecc79b7956ae38c614bc78 Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 22:50:36 2013 -0600 [tests] Start adding tests for hb-set.h Fails now. Fixing. diff --git a/TODO b/TODO index 27ff868..c93b33e 100644 --- a/TODO +++ b/TODO @@ -85,8 +85,6 @@ Tests to write: - GObject, FreeType, etc -- hb_set_t - - hb_cache_t and relatives - hb_feature_to/from_string diff --git a/src/hb-set-private.hh b/src/hb-set-private.hh index c736b69..8e03d68 100644 --- a/src/hb-set-private.hh +++ b/src/hb-set-private.hh @@ -137,6 +137,7 @@ struct hb_set_t { hb_object_header_t header; ASSERT_POD (); + bool in_error; inline void init (void) { header.init (); @@ -224,6 +225,11 @@ struct hb_set_t for (unsigned int i = 0; i < ELTS; i++) elts[i] ^= other->elts[i]; } + inline void invert (void) + { + for (unsigned int i = 0; i < ELTS; i++) + elts[i] = ~elts[i]; + } inline bool next (hb_codepoint_t *codepoint) const { if (unlikely (*codepoint == SENTINEL)) { diff --git a/src/hb-set.cc b/src/hb-set.cc index 93f983a..5f427a5 100644 --- a/src/hb-set.cc +++ b/src/hb-set.cc @@ -49,6 +49,7 @@ hb_set_get_empty (void) { static const hb_set_t _hb_set_nil = { HB_OBJECT_HEADER_STATIC, + true, /* in_error */ {0} /* elts */ }; @@ -93,7 +94,7 @@ hb_set_get_user_data (hb_set_t *set, hb_bool_t hb_set_allocation_successful (const hb_set_t *set HB_UNUSED) { - return true; + return !set->in_error; } void @@ -187,6 +188,12 @@ hb_set_symmetric_difference (hb_set_t *set, set->symmetric_difference (other); } +void +hb_set_invert (hb_set_t *set) +{ + set->invert (); +} + unsigned int hb_set_get_population (const hb_set_t *set) { diff --git a/src/hb-set.h b/src/hb-set.h index ec3d119..291e249 100644 --- a/src/hb-set.h +++ b/src/hb-set.h @@ -121,6 +121,9 @@ void hb_set_symmetric_difference (hb_set_t *set, const hb_set_t *other); +void +hb_set_invert (hb_set_t *set); + unsigned int hb_set_get_population (const hb_set_t *set); diff --git a/test/api/Makefile.am b/test/api/Makefile.am index c5a015f..237f92c 100644 --- a/test/api/Makefile.am +++ b/test/api/Makefile.am @@ -21,6 +21,7 @@ TEST_PROGS = \ test-common \ test-font \ test-object \ + test-set \ test-shape \ test-unicode \ test-version \ diff --git a/test/api/test-set.c b/test/api/test-set.c new file mode 100644 index 0000000..f59760d --- /dev/null +++ b/test/api/test-set.c @@ -0,0 +1,312 @@ +/* + * Copyright © 2013 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): Behdad Esfahbod + */ + +#include "hb-test.h" + +/* Unit tests for hb-set.h */ + + +#if 0 +static void +test_buffer_properties (fixture_t *fixture, gconstpointer user_data) +{ + hb_buffer_t *b = fixture->buffer; + hb_unicode_funcs_t *ufuncs; + + /* test default properties */ + + g_assert (hb_buffer_get_unicode_funcs (b) == hb_unicode_funcs_get_default ()); + g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID); + g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID); + g_assert (hb_buffer_get_language (b) == NULL); + g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT); + + + /* test property changes are retained */ + ufuncs = hb_unicode_funcs_create (NULL); + hb_buffer_set_unicode_funcs (b, ufuncs); + hb_unicode_funcs_destroy (ufuncs); + g_assert (hb_buffer_get_unicode_funcs (b) == ufuncs); + + hb_buffer_set_direction (b, HB_DIRECTION_RTL); + g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_RTL); + + hb_buffer_set_script (b, HB_SCRIPT_ARABIC); + g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC); + + hb_buffer_set_language (b, hb_language_from_string ("fa", -1)); + g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1)); + + hb_buffer_set_flags (b, HB_BUFFER_FLAG_BOT); + g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAG_BOT); + + + + /* test clear clears all properties but unicode_funcs */ + + hb_buffer_clear (b); + + g_assert (hb_buffer_get_unicode_funcs (b) == ufuncs); + g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID); + g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID); + g_assert (hb_buffer_get_language (b) == NULL); + g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT); + + + /* test reset clears all properties */ + + hb_buffer_set_direction (b, HB_DIRECTION_RTL); + g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_RTL); + + hb_buffer_set_script (b, HB_SCRIPT_ARABIC); + g_assert (hb_buffer_get_script (b) == HB_SCRIPT_ARABIC); + + hb_buffer_set_language (b, hb_language_from_string ("fa", -1)); + g_assert (hb_buffer_get_language (b) == hb_language_from_string ("Fa", -1)); + + hb_buffer_set_flags (b, HB_BUFFER_FLAG_BOT); + g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAG_BOT); + + hb_buffer_reset (b); + + g_assert (hb_buffer_get_unicode_funcs (b) == hb_unicode_funcs_get_default ()); + g_assert (hb_buffer_get_direction (b) == HB_DIRECTION_INVALID); + g_assert (hb_buffer_get_script (b) == HB_SCRIPT_INVALID); + g_assert (hb_buffer_get_language (b) == NULL); + g_assert (hb_buffer_get_flags (b) == HB_BUFFER_FLAGS_DEFAULT); +} + +static void +test_buffer_contents (fixture_t *fixture, gconstpointer user_data) +{ + hb_buffer_t *b = fixture->buffer; + unsigned int i, len, len2; + buffer_type_t buffer_type = GPOINTER_TO_INT (user_data); + hb_glyph_info_t *glyphs; + + if (buffer_type == BUFFER_EMPTY) { + g_assert_cmpint (hb_buffer_get_population (b), ==, 0); + return; + } + + len = hb_buffer_get_population (b); + hb_buffer_get_glyph_infos (b, NULL); /* test NULL */ + glyphs = hb_buffer_get_glyph_infos (b, &len2); + g_assert_cmpint (len, ==, len2); + g_assert_cmpint (len, ==, 5); + + for (i = 0; i < len; i++) { + g_assert_cmphex (glyphs[i].mask, ==, 1); + g_assert_cmphex (glyphs[i].var1.u32, ==, 0); + g_assert_cmphex (glyphs[i].var2.u32, ==, 0); + } + + for (i = 0; i < len; i++) { + unsigned int cluster; + cluster = 1+i; + if (i >= 2) { + if (buffer_type == BUFFER_UTF16) + cluster++; + else if (buffer_type == BUFFER_UTF8) + cluster += 3; + } + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + g_assert_cmphex (glyphs[i].cluster, ==, cluster); + } + + /* reverse, test, and reverse back */ + + hb_buffer_reverse (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]); + + hb_buffer_reverse (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + + /* reverse_clusters works same as reverse for now since each codepoint is + * in its own cluster */ + + hb_buffer_reverse_clusters (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]); + + hb_buffer_reverse_clusters (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + + /* now form a cluster and test again */ + glyphs[2].cluster = glyphs[1].cluster; + + /* reverse, test, and reverse back */ + + hb_buffer_reverse (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[len-i]); + + hb_buffer_reverse (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + + /* reverse_clusters twice still should return the original string, + * but when applied once, the 1-2 cluster should be retained. */ + + hb_buffer_reverse_clusters (b); + for (i = 0; i < len; i++) { + unsigned int j = len-1-i; + if (j == 1) + j = 2; + else if (j == 2) + j = 1; + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+j]); + } + + hb_buffer_reverse_clusters (b); + for (i = 0; i < len; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + + + /* test setting length */ + + /* enlarge */ + g_assert (hb_buffer_set_length (b, 10)); + glyphs = hb_buffer_get_glyph_infos (b, NULL); + g_assert_cmpint (hb_buffer_get_population (b), ==, 10); + for (i = 0; i < 5; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + for (i = 5; i < 10; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, 0); + /* shrink */ + g_assert (hb_buffer_set_length (b, 3)); + glyphs = hb_buffer_get_glyph_infos (b, NULL); + g_assert_cmpint (hb_buffer_get_population (b), ==, 3); + for (i = 0; i < 3; i++) + g_assert_cmphex (glyphs[i].codepoint, ==, utf32[1+i]); + + + g_assert (hb_buffer_allocation_successful (b)); + + + /* test reset clears content */ + + hb_buffer_reset (b); + g_assert_cmpint (hb_buffer_get_population (b), ==, 0); +} + +static void +test_buffer_allocation (fixture_t *fixture, gconstpointer user_data) +{ + hb_buffer_t *b = fixture->buffer; + + g_assert_cmpint (hb_buffer_get_population (b), ==, 0); + + g_assert (hb_buffer_pre_allocate (b, 100)); + g_assert_cmpint (hb_buffer_get_population (b), ==, 0); + g_assert (hb_buffer_allocation_successful (b)); + + /* lets try a huge allocation, make sure it fails */ + g_assert (!hb_buffer_pre_allocate (b, (unsigned int) -1)); + g_assert_cmpint (hb_buffer_get_population (b), ==, 0); + g_assert (!hb_buffer_allocation_successful (b)); + + /* small one again */ + g_assert (hb_buffer_pre_allocate (b, 50)); + g_assert_cmpint (hb_buffer_get_population (b), ==, 0); + g_assert (!hb_buffer_allocation_successful (b)); + + hb_buffer_reset (b); + g_assert (hb_buffer_allocation_successful (b)); + + /* all allocation and size */ + g_assert (!hb_buffer_pre_allocate (b, ((unsigned int) -1) / 20 + 1)); + g_assert (!hb_buffer_allocation_successful (b)); + + hb_buffer_reset (b); + g_assert (hb_buffer_allocation_successful (b)); + + /* technically, this one can actually pass on 64bit machines, but + * I'm doubtful that any malloc allows 4GB allocations at a time. + * But let's only enable it on a 32-bit machine. */ + if (sizeof (long) == 4) { + g_assert (!hb_buffer_pre_allocate (b, ((unsigned int) -1) / 20 - 1)); + g_assert (!hb_buffer_allocation_successful (b)); + } + + hb_buffer_reset (b); + g_assert (hb_buffer_allocation_successful (b)); +} +#endif + +static void +test_empty (hb_set_t *b) +{ + g_assert_cmpint (hb_set_get_population (b), ==, 0); + g_assert_cmpint (hb_set_get_min (b), ==, (hb_codepoint_t) -1); + g_assert_cmpint (hb_set_get_max (b), ==, (hb_codepoint_t) -1); +} + +static void +test_set_empty (void) +{ + hb_set_t *b = hb_set_get_empty (); + + g_assert (hb_set_get_empty ()); + g_assert (hb_set_get_empty () == b); + + g_assert (!hb_set_allocation_successful (b)); + + test_empty (b); + + hb_set_add (b, 13); + + test_empty (b); + + hb_set_invert (b); + + test_empty (b); + + g_assert (!hb_set_allocation_successful (b)); + + hb_set_clear (b); + + test_empty (b); + + g_assert (!hb_set_allocation_successful (b)); +} + +int +main (int argc, char **argv) +{ + hb_test_init (&argc, &argv); + +#if 0 + hb_test_add (test_set_algebra); + hb_test_add (test_set_iter); +#endif + hb_test_add (test_set_empty); + + return hb_test_run(); +} commit b9d28f696c433b94c5ffbad8d7c87cf3acff4056 Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 22:49:58 2013 -0600 [tests] Add set object to test-object.c diff --git a/test/api/test-object.c b/test/api/test-object.c index ae4d1cc..3afe6ae 100644 --- a/test/api/test-object.c +++ b/test/api/test-object.c @@ -53,6 +53,17 @@ create_buffer_inert (void) } static void * +create_set (void) +{ + return hb_set_create (); +} +static void * +create_set_inert (void) +{ + return NULL; +} + +static void * create_face (void) { hb_blob_t *blob = (hb_blob_t *) create_blob (); @@ -154,6 +165,7 @@ typedef struct { static const object_t objects[] = { OBJECT_WITHOUT_IMMUTABILITY (buffer), + OBJECT_WITHOUT_IMMUTABILITY (set), OBJECT_WITH_IMMUTABILITY (blob), OBJECT_WITH_IMMUTABILITY (face), OBJECT_WITH_IMMUTABILITY (font), commit 11d2956553f0d4a0086166a04ffc352fcfacf56e Author: Behdad Esfahbod <[email protected]> Date: Wed Jan 2 17:41:27 2013 -0600 Minor diff --git a/src/hb-atomic-private.hh b/src/hb-atomic-private.hh index 111d7a0..67579cd 100644 --- a/src/hb-atomic-private.hh +++ b/src/hb-atomic-private.hh @@ -59,7 +59,7 @@ static inline void HBMemoryBarrier (void) { } #endif -typedef long hb_atomic_int_t; +typedef LONG hb_atomic_int_t; #define hb_atomic_int_add(AI, V) InterlockedExchangeAdd (&(AI), (V)) #define hb_atomic_ptr_get(P) (HBMemoryBarrier (), (void *) *(P))
_______________________________________________ HarfBuzz mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/harfbuzz
