blob: 6d44e074099f86978d47533094af73e33c5daabc [file] [log] [blame]
// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/input_method/ime_rules_config.h"
#include "ash/constants/ash_features.h"
#include "base/json/json_reader.h"
#include "base/logging.h"
#include "base/memory/singleton.h"
#include "base/metrics/field_trial_params.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "url/url_util.h"
namespace ash {
namespace input_method {
namespace {
// String parameter containing the JSON-encoded rules dictionary.
const char kJsonRulesDictKey[] = "json_rules";
constexpr base::FeatureParam<std::string> kFieldTrialParams{
&ash::features::kImeRuleConfig, kJsonRulesDictKey, ""};
// Array of objects, containing the list of rules.
const char kConfigRulesKey[] = "rules";
// Array of strings, containing the list of items the rule will use.
const char kConfigRuleItemsKey[] = "items";
// String, rule name of autocorrect domain denylist, containing the list of
// globally denylisted domains for auto correct..
const char kAutocorrectDomainDenylistKey[] = "ac-domain-denylist";
} // namespace
ImeRulesConfig::ImeRulesConfig() {
InitFromTrialParams();
}
ImeRulesConfig::~ImeRulesConfig() = default;
void ImeRulesConfig::InitFromTrialParams() {
std::string params = kFieldTrialParams.Get();
if (params.empty()) {
VLOG(2) << "Field trial parameter not set";
return;
}
auto dict = base::JSONReader::ReadAndReturnValueWithError(params);
if (!dict.has_value() || !dict->is_dict()) {
VLOG(1) << "Failed to parse field trial params as JSON object: " << params;
if (VLOG_IS_ON(1)) {
if (dict.has_value())
VLOG(1) << "Expecting a dictionary";
else
VLOG(1) << dict.error().message << ", line: " << dict.error().line
<< ", col: " << dict.error().column;
}
return;
}
// Read mandatory list of rules.
auto* rules = dict->FindDictKey(kConfigRulesKey);
if (rules == nullptr || !rules->is_dict()) {
VLOG(1) << "Field trial params did not contain rules";
return;
}
// Read optional rule for auto correct deny list.
auto* ac_domain_denylist = rules->FindDictKey(kAutocorrectDomainDenylistKey);
if (ac_domain_denylist == nullptr || !ac_domain_denylist->is_dict()) {
VLOG(1) << "Rules from config did not contain "
<< kAutocorrectDomainDenylistKey;
} else {
// Read optional list of auto correct denylisted domains.
auto* ac_domains_items =
ac_domain_denylist->FindListKey(kConfigRuleItemsKey);
if (ac_domains_items != nullptr) {
for (const auto& domain : ac_domains_items->GetList()) {
if (domain.is_string()) {
rule_auto_correct_domain_denylist_.push_back(*domain.GetIfString());
}
}
}
}
}
bool ImeRulesConfig::IsAutoCorrectDisabled(
const TextFieldContextualInfo& info) {
// Check the default domain denylist rules.
for (const auto& domain : default_auto_correct_domain_denylist_) {
if (IsSubDomain(info, domain)) {
return true;
}
}
// Check the rule domain denylist rules.
for (const auto& domain : rule_auto_correct_domain_denylist_) {
if (IsSubDomain(info, domain)) {
return true;
}
}
return false;
}
bool ImeRulesConfig::IsSubDomain(const TextFieldContextualInfo& info,
const std::string& domain) {
const size_t registryLength =
net::registry_controlled_domains::GetRegistryLength(
info.tab_url,
net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
if (registryLength == 0) {
return false;
}
const base::StringPiece urlContent = info.tab_url.host_piece();
const base::StringPiece urlDomain =
urlContent.substr(0, urlContent.length() - registryLength - 1);
return url::DomainIs(urlDomain, domain);
}
// static
ImeRulesConfig* ImeRulesConfig::GetInstance() {
return base::Singleton<ImeRulesConfig>::get();
}
} // namespace input_method
} // namespace ash