odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

fontfeaturesettings_test.cpp (12681B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See blend2d.h or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #include "api-build_test_p.h"
      7 #if defined(BL_TEST)
      8 
      9 #include "array_p.h"
     10 #include "fontfeaturesettings_p.h"
     11 #include "fonttagdata_p.h"
     12 #include "object_p.h"
     13 
     14 // bl::FontFeatureSettings - Tests
     15 // ===============================
     16 
     17 namespace bl {
     18 namespace Tests {
     19 
     20 static void verify_font_feature_settings(const BLFontFeatureSettings& ffs) noexcept {
     21   BLFontFeatureSettingsView view;
     22   ffs.get_view(&view);
     23 
     24   if (view.size == 0)
     25     return;
     26 
     27   uint32_t prev_tag = view.data[0].tag;
     28   for (size_t i = 1; i < view.size; i++) {
     29     EXPECT_LT(prev_tag, view.data[i].tag)
     30       .message("BLFontFeatureSettings is corrupted - previous tag 0x%08X is not less than current tag 0x%08X at [%zu]", prev_tag, view.data[i].tag, i);
     31     prev_tag = view.data[i].tag;
     32   }
     33 }
     34 
     35 UNIT(fontfeaturesettings_allocation_strategy, BL_TEST_GROUP_TEXT_CONTAINERS) {
     36   BLFontFeatureSettings ffs;
     37   size_t capacity = ffs.capacity();
     38 
     39   constexpr uint32_t kCharRange = FontTagData::kCharRangeInTag;
     40   constexpr uint32_t kNumItems = FontTagData::kUniqueTagCount / 100;
     41 
     42   for (uint32_t i = 0; i < kNumItems; i++) {
     43     BLTag tag = BL_MAKE_TAG(
     44       uint32_t(' ') + (i / (kCharRange * kCharRange * kCharRange)),
     45       uint32_t(' ') + (i / (kCharRange * kCharRange)) % kCharRange,
     46       uint32_t(' ') + (i / (kCharRange)) % kCharRange,
     47       uint32_t(' ') + (i % kCharRange));
     48 
     49     ffs.set_value(tag, i & 0xFFFFu);
     50     if (capacity != ffs.capacity()) {
     51       size_t impl_size = FontFeatureSettingsInternal::impl_size_from_capacity(ffs.capacity()).value();
     52       INFO("Capacity increased from %zu to %zu [ImplSize=%zu]\n", capacity, ffs.capacity(), impl_size);
     53       capacity = ffs.capacity();
     54     }
     55   }
     56 
     57   verify_font_feature_settings(ffs);
     58 }
     59 
     60 UNIT(fontfeaturesettings, BL_TEST_GROUP_TEXT_CONTAINERS) {
     61   // These are not sorted on purpose to test whether BLFontFeatureSettings would sort them during insertion.
     62   static const uint32_t fat_tags[] = {
     63     BL_MAKE_TAG('r', 'a', 'n', 'd'),
     64     BL_MAKE_TAG('a', 'a', 'l', 't'),
     65     BL_MAKE_TAG('s', 's', '0', '9'),
     66     BL_MAKE_TAG('s', 's', '0', '4')
     67   };
     68 
     69   INFO("SSO initial state");
     70   {
     71     BLFontFeatureSettings ffs;
     72 
     73     EXPECT_TRUE(ffs._d.sso());
     74     EXPECT_TRUE(ffs.is_empty());
     75     EXPECT_EQ(ffs.size(), 0u);
     76     EXPECT_EQ(ffs.capacity(), BLFontFeatureSettings::kSSOCapacity);
     77 
     78     // SSO mode should present all available features as invalid (unassigned).
     79     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
     80       BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
     81       EXPECT_EQ(ffs.get_value(feature_tag), BL_FONT_FEATURE_INVALID_VALUE);
     82     }
     83 
     84     // Trying to get an unknown tag should fail.
     85     EXPECT_EQ(ffs.get_value(BL_MAKE_TAG('-', '-', '-', '-')), BL_FONT_FEATURE_INVALID_VALUE);
     86     EXPECT_EQ(ffs.get_value(BL_MAKE_TAG('a', 'a', 'a', 'a')), BL_FONT_FEATURE_INVALID_VALUE);
     87     EXPECT_EQ(ffs.get_value(BL_MAKE_TAG('z', 'z', 'z', 'z')), BL_FONT_FEATURE_INVALID_VALUE);
     88   }
     89 
     90   INFO("SSO bit tag/value storage");
     91   {
     92     BLFontFeatureSettings ffs;
     93 
     94     // SSO storage must allow to store ALL font features that have bit mapping.
     95     uint32_t num_tags = 0;
     96     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
     97       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
     98         num_tags++;
     99         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    100 
    101         EXPECT_SUCCESS(ffs.set_value(feature_tag, 1u));
    102         EXPECT_EQ(ffs.get_value(feature_tag), 1u);
    103         EXPECT_EQ(ffs.size(), num_tags);
    104         EXPECT_TRUE(ffs._d.sso());
    105 
    106         verify_font_feature_settings(ffs);
    107       }
    108     }
    109 
    110     // Set all features to zero (disabled, but still present in the mapping).
    111     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
    112       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    113         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    114 
    115         EXPECT_SUCCESS(ffs.set_value(feature_tag, 0u));
    116         EXPECT_EQ(ffs.get_value(feature_tag), 0u);
    117         EXPECT_EQ(ffs.size(), num_tags);
    118         EXPECT_TRUE(ffs._d.sso());
    119         verify_font_feature_settings(ffs);
    120       }
    121     }
    122 
    123     // Remove all features.
    124     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
    125       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    126         num_tags--;
    127         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    128 
    129         EXPECT_SUCCESS(ffs.remove_value(feature_tag));
    130         EXPECT_EQ(ffs.get_value(feature_tag), BL_FONT_FEATURE_INVALID_VALUE);
    131         EXPECT_EQ(ffs.size(), num_tags);
    132         EXPECT_TRUE(ffs._d.sso());
    133 
    134         verify_font_feature_settings(ffs);
    135       }
    136     }
    137 
    138     EXPECT_TRUE(ffs.is_empty());
    139     EXPECT_EQ(ffs, BLFontFeatureSettings());
    140   }
    141 
    142   INFO("SSO bit tag/value storage limitations");
    143   {
    144     BLFontFeatureSettings ffs;
    145 
    146     // Trying to set any other value than 0-1 with bit tags fails.
    147     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
    148       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    149         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    150         EXPECT_EQ(ffs.set_value(feature_tag, 2u), BL_ERROR_INVALID_VALUE);
    151       }
    152     }
    153 
    154     EXPECT_TRUE(ffs.is_empty());
    155   }
    156 
    157   INFO("SSO bit tag/value storage + fat tag/value storage");
    158   {
    159     BLFontFeatureSettings ffs;
    160     uint32_t num_tags = 0;
    161 
    162     // Add fat tag/value data.
    163     for (uint32_t i = 0; i < BL_ARRAY_SIZE(fat_tags); i++) {
    164       num_tags++;
    165 
    166       EXPECT_SUCCESS(ffs.set_value(fat_tags[i], 15u));
    167       EXPECT_EQ(ffs.get_value(fat_tags[i]), 15u);
    168       EXPECT_EQ(ffs.size(), num_tags);
    169       EXPECT_TRUE(ffs._d.sso());
    170 
    171       verify_font_feature_settings(ffs);
    172 
    173       // Verify that changing a fat tag's value is working properly (it's bit twiddling).
    174       EXPECT_SUCCESS(ffs.set_value(fat_tags[i], 1u));
    175       EXPECT_EQ(ffs.get_value(fat_tags[i]), 1u);
    176       EXPECT_EQ(ffs.size(), num_tags);
    177       EXPECT_TRUE(ffs._d.sso());
    178 
    179       verify_font_feature_settings(ffs);
    180     }
    181 
    182     // Add bit tag/value data.
    183     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
    184       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    185         num_tags++;
    186         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    187 
    188         EXPECT_SUCCESS(ffs.set_value(feature_tag, 1u));
    189         EXPECT_EQ(ffs.get_value(feature_tag), 1u);
    190         EXPECT_EQ(ffs.size(), num_tags);
    191         EXPECT_TRUE(ffs._d.sso());
    192 
    193         verify_font_feature_settings(ffs);
    194       }
    195     }
    196 
    197     // Remove fat tag/value data.
    198     for (uint32_t i = 0; i < BL_ARRAY_SIZE(fat_tags); i++) {
    199       num_tags--;
    200 
    201       EXPECT_SUCCESS(ffs.remove_value(fat_tags[i]));
    202       EXPECT_EQ(ffs.size(), num_tags);
    203       EXPECT_TRUE(ffs._d.sso());
    204 
    205       verify_font_feature_settings(ffs);
    206     }
    207 
    208     // Remove bit tag/value data.
    209     for (uint32_t feature_id = 0; feature_id < FontTagData::kFeatureIdCount; feature_id++) {
    210       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    211         num_tags--;
    212         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    213 
    214         EXPECT_SUCCESS(ffs.remove_value(feature_tag));
    215         EXPECT_EQ(ffs.size(), num_tags);
    216         EXPECT_TRUE(ffs._d.sso());
    217 
    218         verify_font_feature_settings(ffs);
    219       }
    220     }
    221 
    222     EXPECT_TRUE(ffs.is_empty());
    223     EXPECT_EQ(ffs, BLFontFeatureSettings());
    224   }
    225 
    226   INFO("SSO tag/value equality");
    227   {
    228     BLFontFeatureSettings ffsA;
    229     BLFontFeatureSettings ffsB;
    230 
    231     // Assign bit tag/value data.
    232     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    233       uint32_t feature_id = i;
    234       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    235         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    236         EXPECT_SUCCESS(ffsA.set_value(feature_tag, 1u));
    237         verify_font_feature_settings(ffsA);
    238       }
    239     }
    240 
    241     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    242       uint32_t feature_id = FontTagData::kFeatureIdCount - 1 - i;
    243       if (FontTagData::feature_info_table[feature_id].has_bit_id()) {
    244         BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    245         EXPECT_SUCCESS(ffsB.set_value(feature_tag, 1u));
    246         verify_font_feature_settings(ffsB);
    247       }
    248     }
    249 
    250     EXPECT_EQ(ffsA, ffsB);
    251 
    252     // Assign fat tag/value data.
    253     for (uint32_t i = 0; i < BL_ARRAY_SIZE(fat_tags); i++) {
    254       EXPECT_SUCCESS(ffsA.set_value(fat_tags[i], i));
    255       verify_font_feature_settings(ffsA);
    256     }
    257 
    258     for (uint32_t iRev = 0; iRev < BL_ARRAY_SIZE(fat_tags); iRev++) {
    259       uint32_t i = BL_ARRAY_SIZE(fat_tags) - 1 - iRev;
    260       EXPECT_SUCCESS(ffsB.set_value(fat_tags[i], i));
    261       verify_font_feature_settings(ffsB);
    262     }
    263 
    264     EXPECT_EQ(ffsA, ffsB);
    265 
    266     // Remove fat tag/value data.
    267     for (uint32_t i = 0; i < BL_ARRAY_SIZE(fat_tags); i++) {
    268       EXPECT_SUCCESS(ffsA.remove_value(fat_tags[i]));
    269       verify_font_feature_settings(ffsA);
    270     }
    271 
    272     for (uint32_t iRev = 0; iRev < BL_ARRAY_SIZE(fat_tags); iRev++) {
    273       uint32_t i = BL_ARRAY_SIZE(fat_tags) - 1 - iRev;
    274       EXPECT_SUCCESS(ffsB.remove_value(fat_tags[i]));
    275       verify_font_feature_settings(ffsB);
    276     }
    277 
    278     EXPECT_EQ(ffsA, ffsB);
    279   }
    280 
    281   INFO("Dynamic representation");
    282   {
    283     BLFontFeatureSettings ffs;
    284 
    285     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    286       uint32_t feature_id = FontTagData::kFeatureIdCount - 1 - i;
    287       BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    288       EXPECT_SUCCESS(ffs.set_value(feature_tag, 1u));
    289       EXPECT_EQ(ffs.get_value(feature_tag), 1u);
    290       EXPECT_EQ(ffs.size(), i + 1u);
    291       verify_font_feature_settings(ffs);
    292     }
    293 
    294     EXPECT_FALSE(ffs._d.sso());
    295 
    296     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    297       uint32_t feature_id = FontTagData::kFeatureIdCount - 1 - i;
    298       BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    299 
    300       if (!FontTagData::feature_info_table[feature_id].has_bit_id()) {
    301         EXPECT_SUCCESS(ffs.set_value(feature_tag, 65535u));
    302         EXPECT_EQ(ffs.get_value(feature_tag), 65535u);
    303       }
    304       else {
    305         EXPECT_SUCCESS(ffs.set_value(feature_tag, 0u));
    306         EXPECT_EQ(ffs.get_value(feature_tag), 0u);
    307       }
    308 
    309       verify_font_feature_settings(ffs);
    310     }
    311 
    312     EXPECT_FALSE(ffs._d.sso());
    313 
    314     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    315       uint32_t feature_id = i;
    316       BLTag feature_tag = FontTagData::feature_id_to_tag_table[feature_id];
    317 
    318       EXPECT_SUCCESS(ffs.remove_value(feature_tag));
    319       EXPECT_EQ(ffs.get_value(feature_tag), BL_FONT_FEATURE_INVALID_VALUE);
    320 
    321       verify_font_feature_settings(ffs);
    322     }
    323 
    324     EXPECT_TRUE(ffs.is_empty());
    325     EXPECT_EQ(ffs.size(), 0u);
    326     EXPECT_FALSE(ffs._d.sso());
    327 
    328   }
    329 
    330   INFO("Dynamic tag/value equality");
    331   {
    332     BLFontFeatureSettings ffs1;
    333     BLFontFeatureSettings ffs2;
    334 
    335     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    336       EXPECT_SUCCESS(ffs1.set_value(FontTagData::feature_id_to_tag_table[i], 1u));
    337       EXPECT_SUCCESS(ffs2.set_value(FontTagData::feature_id_to_tag_table[FontTagData::kFeatureIdCount - 1u - i], 1u));
    338 
    339       verify_font_feature_settings(ffs1);
    340       verify_font_feature_settings(ffs2);
    341     }
    342 
    343     EXPECT_EQ(ffs1, ffs2);
    344   }
    345 
    346   INFO("Dynamic tag/value vs SSO tag/value equality");
    347   {
    348     BLFontFeatureSettings ffs1;
    349     BLFontFeatureSettings ffs2;
    350 
    351     for (uint32_t i = 0; i < FontTagData::kFeatureIdCount; i++) {
    352       if (FontTagData::feature_info_table[i].has_bit_id()) {
    353         EXPECT_SUCCESS(ffs1.set_value(FontTagData::feature_id_to_tag_table[i], 1u));
    354         EXPECT_SUCCESS(ffs2.set_value(FontTagData::feature_id_to_tag_table[i], 1u));
    355 
    356         verify_font_feature_settings(ffs1);
    357         verify_font_feature_settings(ffs2);
    358       }
    359     }
    360 
    361     EXPECT_EQ(ffs1, ffs2);
    362 
    363     // Make ffs1 go out of SSO mode.
    364     EXPECT_SUCCESS(ffs1.set_value(BL_MAKE_TAG('a', 'a', 'a', 'a'), 1000));
    365     EXPECT_SUCCESS(ffs1.remove_value(BL_MAKE_TAG('a', 'a', 'a', 'a')));
    366     EXPECT_EQ(ffs1, ffs2);
    367     EXPECT_EQ(ffs2, ffs1);
    368 
    369     // Make ffs2 go out of SSO mode.
    370     EXPECT_SUCCESS(ffs2.set_value(BL_MAKE_TAG('a', 'a', 'a', 'a'), 1000));
    371     EXPECT_SUCCESS(ffs2.remove_value(BL_MAKE_TAG('a', 'a', 'a', 'a')));
    372     EXPECT_EQ(ffs1, ffs2);
    373     EXPECT_EQ(ffs2, ffs1);
    374   }
    375 }
    376 
    377 } // {Tests}
    378 } // {bl}
    379 
    380 #endif // BL_TEST