Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bb804807 authored by Siyamed Sinir's avatar Siyamed Sinir Committed by Android (Google) Code Review
Browse files

Merge "Use numbering system for configuration selection."

parents 411985ba 7ec28a88
Loading
Loading
Loading
Loading
+58 −27
Original line number Diff line number Diff line
@@ -1877,19 +1877,27 @@ void ResTable_config::swapHtoD() {
        return (l.locale > r.locale) ? 1 : -1;
    }

    // The language & region are equal, so compare the scripts and variants.
    // The language & region are equal, so compare the scripts, variants and
    // numbering systms in this order. Comparison of variants and numbering
    // systems should happen very infrequently (if at all.)
    // The comparison code relies on memcmp low-level optimizations that make it
    // more efficient than strncmp.
    const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
    const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
    const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;

    int script = memcmp(lScript, rScript, sizeof(l.localeScript));
    if (script) {
        return script;
    }

    // The language, region and script are equal, so compare variants.
    //
    // This should happen very infrequently (if at all.)
    return memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant));
    int variant = memcmp(l.localeVariant, r.localeVariant, sizeof(l.localeVariant));
    if (variant) {
        return variant;
    }

    return memcmp(l.localeNumberingSystem, r.localeNumberingSystem,
                  sizeof(l.localeNumberingSystem));
}

int ResTable_config::compare(const ResTable_config& o) const {
@@ -2030,6 +2038,22 @@ int ResTable_config::diff(const ResTable_config& o) const {
    return diffs;
}

// There isn't a well specified "importance" order between variants and
// scripts. We can't easily tell whether, say "en-Latn-US" is more or less
// specific than "en-US-POSIX".
//
// We therefore arbitrarily decide to give priority to variants over
// scripts since it seems more useful to do so. We will consider
// "en-US-POSIX" to be more specific than "en-Latn-US".
//
// Unicode extension keywords are considered to be less important than
// scripts and variants.
inline int ResTable_config::getImportanceScoreOfLocale() const {
  return (localeVariant[0] ? 4 : 0)
      + (localeScript[0] && !localeScriptWasComputed ? 2: 0)
      + (localeNumberingSystem[0] ? 1: 0);
}

int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
    if (locale || o.locale) {
        if (language[0] != o.language[0]) {
@@ -2043,21 +2067,7 @@ int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
        }
    }

    // There isn't a well specified "importance" order between variants and
    // scripts. We can't easily tell whether, say "en-Latn-US" is more or less
    // specific than "en-US-POSIX".
    //
    // We therefore arbitrarily decide to give priority to variants over
    // scripts since it seems more useful to do so. We will consider
    // "en-US-POSIX" to be more specific than "en-Latn-US".

    const int score = ((localeScript[0] != '\0' && !localeScriptWasComputed) ? 1 : 0) +
        ((localeVariant[0] != '\0') ? 2 : 0);

    const int oScore = (o.localeScript[0] != '\0' && !o.localeScriptWasComputed ? 1 : 0) +
        ((o.localeVariant[0] != '\0') ? 2 : 0);

    return score - oScore;
    return getImportanceScoreOfLocale() - o.getImportanceScoreOfLocale();
}

bool ResTable_config::isMoreSpecificThan(const ResTable_config& o) const {
@@ -2314,6 +2324,17 @@ bool ResTable_config::isLocaleBetterThan(const ResTable_config& o,
        return localeMatches;
    }

    // The variants are the same, try numbering system.
    const bool localeNumsysMatches = strncmp(localeNumberingSystem,
                                             requested->localeNumberingSystem,
                                             sizeof(localeNumberingSystem)) == 0;
    const bool otherNumsysMatches = strncmp(o.localeNumberingSystem,
                                            requested->localeNumberingSystem,
                                            sizeof(localeNumberingSystem)) == 0;
    if (localeNumsysMatches != otherNumsysMatches) {
        return localeNumsysMatches;
    }

    // Finally, the languages, although equivalent, may still be different
    // (like for Tagalog and Filipino). Identical is better than just
    // equivalent.
@@ -2781,7 +2802,7 @@ void ResTable_config::appendDirLocale(String8& out) const {
        return;
    }
    const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
    if (!scriptWasProvided && !localeVariant[0]) {
    if (!scriptWasProvided && !localeVariant[0] && !localeNumberingSystem[0]) {
        // Legacy format.
        if (out.size() > 0) {
            out.append("-");
@@ -2826,6 +2847,12 @@ void ResTable_config::appendDirLocale(String8& out) const {
        out.append("+");
        out.append(localeVariant, strnlen(localeVariant, sizeof(localeVariant)));
    }

    if (localeNumberingSystem[0]) {
        out.append("+u+nu+");
        out.append(localeNumberingSystem,
                   strnlen(localeNumberingSystem, sizeof(localeNumberingSystem)));
    }
}

void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool canonicalize) const {
@@ -2868,10 +2895,17 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN], bool can
            str[charsWritten++] = '-';
        }
        memcpy(str + charsWritten, localeVariant, sizeof(localeVariant));
        charsWritten += strnlen(str + charsWritten, sizeof(localeVariant));
    }

    /* TODO: Add BCP47 extension. It requires RESTABLE_MAX_LOCALE_LEN
     * increase from 28 to 42 bytes (-u-nu-xxxxxxxx) */
    // Add Unicode extension only if at least one other locale component is present
    if (localeNumberingSystem[0] != '\0' && charsWritten > 0) {
        static constexpr char NU_PREFIX[] = "-u-nu-";
        static constexpr size_t NU_PREFIX_LEN = sizeof(NU_PREFIX) - 1;
        memcpy(str + charsWritten, NU_PREFIX, NU_PREFIX_LEN);
        charsWritten += NU_PREFIX_LEN;
        memcpy(str + charsWritten, localeNumberingSystem, sizeof(localeNumberingSystem));
    }
}

struct LocaleParserState {
@@ -3004,10 +3038,7 @@ struct LocaleParserState {
}

void ResTable_config::setBcp47Locale(const char* in) {
    locale = 0;
    memset(localeScript, 0, sizeof(localeScript));
    memset(localeVariant, 0, sizeof(localeVariant));
    memset(localeNumberingSystem, 0, sizeof(localeNumberingSystem));
    clearLocale();

    const char* start = in;
    LocaleParserState state;
+7 −3
Original line number Diff line number Diff line
@@ -894,9 +894,10 @@ struct ResTable_package
// - a 8 char variant code prefixed by a 'v'
//
// each separated by a single char separator, which sums up to a total of 24
// chars, (25 include the string terminator) rounded up to 28 to be 4 byte
// aligned.
#define RESTABLE_MAX_LOCALE_LEN 28
// chars, (25 include the string terminator). Numbering system specificator,
// if present, can add up to 14 bytes (-u-nu-xxxxxxxx), giving 39 bytes,
// or 40 bytes to make it 4 bytes aligned.
#define RESTABLE_MAX_LOCALE_LEN 40


/**
@@ -1303,6 +1304,9 @@ struct ResTable_config
    // and 0 if they're equally specific.
    int isLocaleMoreSpecificThan(const ResTable_config &o) const;

    // Returns an integer representng the imporance score of the configuration locale.
    int getImportanceScoreOfLocale() const;

    // Return true if 'this' is a better locale match than 'o' for the
    // 'requested' configuration. Similar to isBetterThan(), this assumes that
    // match() has already been used to remove any configurations that don't
+53 −0
Original line number Diff line number Diff line
@@ -173,6 +173,18 @@ TEST(ConfigLocaleTest, IsMoreSpecificThan) {
    fillIn("en", "US", NULL, "POSIX", &r);
    EXPECT_FALSE(l.isMoreSpecificThan(r));
    EXPECT_TRUE(r.isMoreSpecificThan(l));

    fillIn("ar", "EG", NULL, NULL, &l);
    fillIn("ar", "EG", NULL, NULL, &r);
    memcpy(&r.localeNumberingSystem, "latn", 4);
    EXPECT_FALSE(l.isMoreSpecificThan(r));
    EXPECT_TRUE(r.isMoreSpecificThan(l));

    fillIn("en", "US", NULL, NULL, &l);
    fillIn("es", "ES", NULL, NULL, &r);

    EXPECT_FALSE(l.isMoreSpecificThan(r));
    EXPECT_FALSE(r.isMoreSpecificThan(l));
}

TEST(ConfigLocaleTest, setLocale) {
@@ -321,6 +333,22 @@ TEST(ConfigLocaleTest, getBcp47Locale_script) {
    EXPECT_EQ(0, strcmp("en", out));
}

TEST(ConfigLocaleTest, getBcp47Locale_numberingSystem) {
    ResTable_config config;
    fillIn("en", NULL, NULL, NULL, &config);

    char out[RESTABLE_MAX_LOCALE_LEN];

    memcpy(&config.localeNumberingSystem, "latn", 4);
    config.getBcp47Locale(out);
    EXPECT_EQ(0, strcmp("en-u-nu-latn", out));

    fillIn("sr", "SR", "Latn", NULL, &config);
    memcpy(&config.localeNumberingSystem, "latn", 4);
    config.getBcp47Locale(out);
    EXPECT_EQ(0, strcmp("sr-Latn-SR-u-nu-latn", out));
}

TEST(ConfigLocaleTest, getBcp47Locale_canonicalize) {
    ResTable_config config;
    char out[RESTABLE_MAX_LOCALE_LEN];
@@ -433,6 +461,11 @@ TEST(ConfigLocaleTest, match) {
    fillIn("ar", "XB", NULL, NULL, &requested);
    // Even if they are pseudo-locales, exactly equal locales match.
    EXPECT_TRUE(supported.match(requested));

    fillIn("ar", "EG", NULL, NULL, &supported);
    fillIn("ar", "TN", NULL, NULL, &requested);
    memcpy(&supported.localeNumberingSystem, "latn", 4);
    EXPECT_TRUE(supported.match(requested));
}

TEST(ConfigLocaleTest, match_emptyScript) {
@@ -758,6 +791,26 @@ TEST(ConfigLocaleTest, isLocaleBetterThan_regionComparison) {
    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));
}

TEST(ConfigLocaleTest, isLocaleBetterThan_numberingSystem) {
    ResTable_config config1, config2, request;

    fillIn("ar", "EG", NULL, NULL, &request);
    memcpy(&request.localeNumberingSystem, "latn", 4);
    fillIn("ar", NULL, NULL, NULL, &config1);
    memcpy(&config1.localeNumberingSystem, "latn", 4);
    fillIn("ar", NULL, NULL, NULL, &config2);
    EXPECT_TRUE(config1.isLocaleBetterThan(config2, &request));
    EXPECT_FALSE(config2.isLocaleBetterThan(config1, &request));

    fillIn("ar", "EG", NULL, NULL, &request);
    memcpy(&request.localeNumberingSystem, "latn", 4);
    fillIn("ar", "TN", NULL, NULL, &config1);
    memcpy(&config1.localeNumberingSystem, "latn", 4);
    fillIn("ar", NULL, NULL, NULL, &config2);
    EXPECT_TRUE(config2.isLocaleBetterThan(config1, &request));
    EXPECT_FALSE(config1.isLocaleBetterThan(config2, &request));
}

// Default resources are considered better matches for US English
// and US-like English locales than International English locales
TEST(ConfigLocaleTest, isLocaleBetterThan_UsEnglishIsSpecial) {