summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorgrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 14:01:21 +0000
committergrt@chromium.org <grt@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-10-20 14:01:21 +0000
commit6ae3d4909757757f27940369e1bdc67eebd52b87 (patch)
treeb95726d81214d6824646008e53d870d0ee8f2feb
parentb85e5120573c61b9bdd492fb903b334bf1119d8f (diff)
downloadchromium_src-6ae3d4909757757f27940369e1bdc67eebd52b87.zip
chromium_src-6ae3d4909757757f27940369e1bdc67eebd52b87.tar.gz
chromium_src-6ae3d4909757757f27940369e1bdc67eebd52b87.tar.bz2
Various changes to make GCF nicer for the non-en-US world:
- Chrome Frame now uses MUI on Vista+ to detect IE's UX language. - Chrome Frame now tells Chrome (via the --lang command-line option) what the current langauge is. - Chrome Frame now respects Chrome's "ApplicationLocaleValue" group policy setting. BUG=56435,59582 TEST=chrome_frame_unittests and chrome_frame_tests updated Review URL: http://codereview.chromium.org/3757007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63208 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome_frame/chrome_frame_activex_base.h17
-rw-r--r--chrome_frame/chrome_frame_automation.cc9
-rw-r--r--chrome_frame/chrome_frame_automation.h12
-rw-r--r--chrome_frame/chrome_frame_npapi_unittest.cc19
-rw-r--r--chrome_frame/chrome_frame_plugin.h5
-rw-r--r--chrome_frame/chrome_launcher.cc1
-rw-r--r--chrome_frame/policy_settings.cc93
-rw-r--r--chrome_frame/policy_settings.h19
-rw-r--r--chrome_frame/simple_resource_loader.cc288
-rw-r--r--chrome_frame/simple_resource_loader.h53
-rw-r--r--chrome_frame/test/automation_client_mock.cc16
-rw-r--r--chrome_frame/test/chrome_frame_automation_mock.h14
-rw-r--r--chrome_frame/test/policy_settings_unittest.cc35
-rw-r--r--chrome_frame/test/proxy_factory_mock.cc10
-rw-r--r--chrome_frame/test/simple_resource_loader_test.cc76
15 files changed, 521 insertions, 146 deletions
diff --git a/chrome_frame/chrome_frame_activex_base.h b/chrome_frame/chrome_frame_activex_base.h
index 264621f..5f063c8 100644
--- a/chrome_frame/chrome_frame_activex_base.h
+++ b/chrome_frame/chrome_frame_activex_base.h
@@ -177,7 +177,8 @@ class ATL_NO_VTABLE ChromeFrameActivexBase : // NOLINT
: ready_state_(READYSTATE_UNINITIALIZED),
url_fetcher_(new UrlmonUrlRequestManager()),
failed_to_fetch_in_place_frame_(false),
- draw_sad_tab_(false) {
+ draw_sad_tab_(false),
+ prev_resource_instance_(NULL) {
m_bWindowOnly = TRUE;
url_fetcher_->set_container(static_cast<IDispatch*>(this));
}
@@ -244,10 +245,16 @@ END_MSG_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
virtual void SetResourceModule() {
+ DCHECK(NULL == prev_resource_instance_);
SimpleResourceLoader* loader_instance = SimpleResourceLoader::instance();
DCHECK(loader_instance);
- HINSTANCE res_dll = loader_instance->GetResourceModuleHandle();
- _AtlBaseModule.SetResourceInstance(res_dll);
+ HMODULE res_dll = loader_instance->GetResourceModuleHandle();
+ prev_resource_instance_ = _AtlBaseModule.SetResourceInstance(res_dll);
+ }
+
+ virtual void ClearResourceModule() {
+ _AtlBaseModule.SetResourceInstance(prev_resource_instance_);
+ prev_resource_instance_ = NULL;
}
HRESULT FinalConstruct() {
@@ -272,6 +279,8 @@ END_MSG_MAP()
void FinalRelease() {
Uninitialize();
+
+ ClearResourceModule();
}
void ResetUrlRequestManager() {
@@ -1243,6 +1252,8 @@ END_MSG_MAP()
// Handle network requests when host network stack is used. Passed to the
// automation client on initialization.
scoped_ptr<UrlmonUrlRequestManager> url_fetcher_;
+
+ HINSTANCE prev_resource_instance_;
};
#endif // CHROME_FRAME_CHROME_FRAME_ACTIVEX_BASE_H_
diff --git a/chrome_frame/chrome_frame_automation.cc b/chrome_frame/chrome_frame_automation.cc
index 7c79287..7ee5950 100644
--- a/chrome_frame/chrome_frame_automation.cc
+++ b/chrome_frame/chrome_frame_automation.cc
@@ -4,6 +4,7 @@
#include "chrome_frame/chrome_frame_automation.h"
+#include "app/app_switches.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/compiler_specific.h"
@@ -26,6 +27,7 @@
#include "chrome_frame/chrome_launcher_utils.h"
#include "chrome_frame/crash_reporting/crash_metrics.h"
#include "chrome_frame/custom_sync_call_context.h"
+#include "chrome_frame/simple_resource_loader.h"
#include "chrome_frame/utils.h"
#ifdef NDEBUG
@@ -299,6 +301,9 @@ void AutomationProxyCacheEntry::CreateProxy(ChromeFrameLaunchParams* params,
command_line->AppendSwitchPath(switches::kUserDataDir,
params->profile_path());
+ if (!params->language().empty())
+ command_line->AppendSwitchNative(switches::kLang, params->language());
+
std::wstring command_line_string(command_line->command_line_string());
// If there are any extra arguments, append them to the command line.
if (!params->extra_arguments().empty()) {
@@ -720,8 +725,8 @@ bool ChromeFrameAutomationClient::InitiateNavigation(const std::string& url,
if (!chrome_launch_params_) {
FilePath profile_path;
chrome_launch_params_ = new ChromeFrameLaunchParams(parsed_url,
- referrer_gurl, profile_path, L"", L"", false, false,
- route_all_top_level_navigations_);
+ referrer_gurl, profile_path, L"", SimpleResourceLoader::GetLanguage(),
+ L"", false, false, route_all_top_level_navigations_);
} else {
chrome_launch_params_->set_referrer(referrer_gurl);
chrome_launch_params_->set_url(parsed_url);
diff --git a/chrome_frame/chrome_frame_automation.h b/chrome_frame/chrome_frame_automation.h
index 8500ee7..47b03c0 100644
--- a/chrome_frame/chrome_frame_automation.h
+++ b/chrome_frame/chrome_frame_automation.h
@@ -109,14 +109,15 @@ class ChromeFrameLaunchParams : // NOLINT
ChromeFrameLaunchParams(const GURL& url, const GURL& referrer,
const FilePath& profile_path,
const std::wstring& profile_name,
+ const std::wstring& language,
const std::wstring& extra_arguments,
bool incognito, bool widget_mode,
bool route_all_top_level_navigations)
: launch_timeout_(kCommandExecutionTimeout), url_(url),
referrer_(referrer), profile_path_(profile_path),
- profile_name_(profile_name), extra_arguments_(extra_arguments),
- version_check_(true), incognito_mode_(incognito),
- is_widget_mode_(widget_mode),
+ profile_name_(profile_name), language_(language),
+ extra_arguments_(extra_arguments), version_check_(true),
+ incognito_mode_(incognito), is_widget_mode_(widget_mode),
route_all_top_level_navigations_(route_all_top_level_navigations) {
}
@@ -155,6 +156,10 @@ class ChromeFrameLaunchParams : // NOLINT
return profile_name_;
}
+ const std::wstring& language() const {
+ return language_;
+ }
+
const std::wstring& extra_arguments() const {
return extra_arguments_;
}
@@ -190,6 +195,7 @@ class ChromeFrameLaunchParams : // NOLINT
GURL referrer_;
FilePath profile_path_;
std::wstring profile_name_;
+ std::wstring language_;
std::wstring extra_arguments_;
bool version_check_;
bool incognito_mode_;
diff --git a/chrome_frame/chrome_frame_npapi_unittest.cc b/chrome_frame/chrome_frame_npapi_unittest.cc
index c0a0208..34194440 100644
--- a/chrome_frame/chrome_frame_npapi_unittest.cc
+++ b/chrome_frame/chrome_frame_npapi_unittest.cc
@@ -125,6 +125,7 @@ class TestNPAPIPrivilegedApi: public ::testing::Test {
bool expect_privilege_check,
bool is_privileged,
const std::wstring& profile_name,
+ const std::wstring& language,
const std::wstring& extra_args) {
EXPECT_CALL(mock_api, GetLocation())
.WillOnce(Return(std::string("http://www.google.com")));
@@ -137,7 +138,7 @@ class TestNPAPIPrivilegedApi: public ::testing::Test {
scoped_refptr<ChromeFrameLaunchParams> launch_params(
new ChromeFrameLaunchParams(GURL(), GURL(), FilePath(), profile_name,
- extra_args, is_incognito, true, false));
+ language, extra_args, is_incognito, true, false));
EXPECT_CALL(*mock_automation,
Initialize(_, LaunchParamEq(true, extra_args, is_incognito, true)))
@@ -177,6 +178,7 @@ TEST_F(TestNPAPIPrivilegedApi, NoPrivilegeCheckWhenNoArguments) {
false, // Fail if privilege check is invoked.
false,
kDefaultProfileName,
+ L"", // No specific language override.
L""); // No extra args to initialize.
// No arguments, no privilege requested.
@@ -191,6 +193,7 @@ TEST_F(TestNPAPIPrivilegedApi, NoPrivilegeCheckWhenZeroArgument) {
false, // Fail if privilege check is invoked.
false,
kDefaultProfileName,
+ L"", // No specific language override.
L""); // No extra args to initialize.
// Privileged mode explicitly zero.
@@ -207,6 +210,7 @@ TEST_F(TestNPAPIPrivilegedApi, NotPrivilegedDoesNotAllowArgsOrProfile) {
true, // Fail unless privilege check is invoked.
false, // Not privileged.
kDefaultProfileName,
+ L"", // No specific language override.
L""); // No extra arguments allowed.
char* argn[] = {
@@ -227,9 +231,10 @@ TEST_F(TestNPAPIPrivilegedApi, NotPrivilegedDoesNotAllowArgsOrProfile) {
TEST_F(TestNPAPIPrivilegedApi, PrivilegedAllowsArgsAndProfile) {
SetupPrivilegeTest(false, // Not incognito.
- true, // Fail unless privilege check is invoked.
- true, // Privileged mode.
+ true, // Fail unless privilege check is invoked.
+ true, // Privileged mode.
L"custom_profile_name", // Custom profile expected.
+ L"", // No specific language override.
L"-bar=far"); // Extra arguments expected
// With privileged mode we expect automation to be enabled.
@@ -428,8 +433,9 @@ TEST_F(TestNPAPIPrivilegedProperty,
// Attempt setting onprivatemessage when not privileged.
SetupPrivilegeTest(false, // not incognito.
true, // expect privilege check.
- false, // not privileged.
+ false, // not privileged.
kDefaultProfileName,
+ L"", // No specific language override.
L"");
char* on_private_message_str = "onprivatemessage()";
@@ -464,6 +470,7 @@ TEST_F(TestNPAPIPrivilegedProperty,
true, // expect privilege check.
true, // privileged.
kDefaultProfileName,
+ L"", // No specific language override.
L"");
char* on_private_message_str = "onprivatemessage()";
@@ -499,8 +506,9 @@ TEST_F(TestNPAPIPrivilegedProperty,
// Assigning to onprivatemessage when not privileged should fail.
SetupPrivilegeTest(false, // not incognito.
true, // expect privilege check.
- false, // not privileged.
+ false, // not privileged.
kDefaultProfileName,
+ L"", // No specific language override.
L"");
char* argn = "privileged_mode";
@@ -529,6 +537,7 @@ TEST_F(TestNPAPIPrivilegedProperty,
true, // expect privilege check.
true, // privileged.
kDefaultProfileName,
+ L"", // No specific language override.
L"");
char* argn = "privileged_mode";
diff --git a/chrome_frame/chrome_frame_plugin.h b/chrome_frame/chrome_frame_plugin.h
index 27e192e..9ea6ce9 100644
--- a/chrome_frame/chrome_frame_plugin.h
+++ b/chrome_frame/chrome_frame_plugin.h
@@ -75,8 +75,9 @@ END_MSG_MAP()
// is Google Chrome Frame.
FilePath actual_profile_name = profile_path.BaseName();
launch_params_ = new ChromeFrameLaunchParams(url, referrer, profile_path,
- actual_profile_name.value(), extra_chrome_arguments, incognito_mode,
- is_widget_mode, route_all_top_level_navigations);
+ actual_profile_name.value(), SimpleResourceLoader::GetLanguage(),
+ extra_chrome_arguments, incognito_mode, is_widget_mode,
+ route_all_top_level_navigations);
return automation_client_->Initialize(this, launch_params_);
}
diff --git a/chrome_frame/chrome_launcher.cc b/chrome_frame/chrome_launcher.cc
index f040d2b..a8ff329 100644
--- a/chrome_frame/chrome_launcher.cc
+++ b/chrome_frame/chrome_launcher.cc
@@ -23,6 +23,7 @@ const wchar_t* kAllowedSwitches[] = {
L"disable-renderer-accessibility",
L"enable-experimental-extension-apis",
L"force-renderer-accessibility",
+ L"lang",
L"no-default-browser-check",
L"noerrdialogs",
L"no-first-run",
diff --git a/chrome_frame/policy_settings.cc b/chrome_frame/policy_settings.cc
index 834d6cc..1a35d67 100644
--- a/chrome_frame/policy_settings.cc
+++ b/chrome_frame/policy_settings.cc
@@ -4,6 +4,8 @@
#include "chrome_frame/policy_settings.h"
+#include <algorithm>
+
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
@@ -11,6 +13,18 @@
#include "chrome/common/policy_constants.h"
#include "chrome_frame/utils.h"
+namespace {
+
+// This array specifies the order in which registry keys are tested. Do not
+// change this unless the decision is made product-wide (i.e., in Chrome's
+// configuration policy provider).
+const HKEY kRootKeys[] = {
+ HKEY_LOCAL_MACHINE,
+ HKEY_CURRENT_USER
+};
+
+} // namespace
+
PolicySettings::RendererForUrl PolicySettings::GetRendererForUrl(
const wchar_t* url) {
RendererForUrl renderer = default_renderer_;
@@ -41,21 +55,24 @@ PolicySettings::RendererForUrl PolicySettings::GetRendererForContentType(
return renderer;
}
-void PolicySettings::RefreshFromRegistry() {
- default_renderer_ = RENDERER_NOT_SPECIFIED;
- renderer_exclusion_list_.clear();
+// static
+void PolicySettings::ReadUrlSettings(
+ RendererForUrl* default_renderer,
+ std::vector<std::wstring>* renderer_exclusion_list) {
+ DCHECK(default_renderer);
+ DCHECK(renderer_exclusion_list);
+
+ *default_renderer = RENDERER_NOT_SPECIFIED;
+ renderer_exclusion_list->clear();
base::win::RegKey config_key;
DWORD value = RENDERER_NOT_SPECIFIED;
- HKEY root_key[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
std::wstring settings_value(
ASCIIToWide(policy::key::kChromeFrameRendererSettings));
- for (int i = 0; i < arraysize(root_key); ++i) {
- if (config_key.Open(root_key[i], policy::kRegistrySubKey, KEY_READ) &&
+ for (int i = 0; i < arraysize(kRootKeys); ++i) {
+ if (config_key.Open(kRootKeys[i], policy::kRegistrySubKey, KEY_READ) &&
config_key.ReadValueDW(settings_value.c_str(), &value)) {
break;
- } else {
- config_key.Close();
}
}
@@ -67,26 +84,72 @@ void PolicySettings::RefreshFromRegistry() {
if (value != RENDER_IN_HOST && value != RENDER_IN_CHROME_FRAME) {
DVLOG(1) << "default renderer not specified via policy";
} else {
- default_renderer_ = static_cast<RendererForUrl>(value);
- const char* exclusion_list_name = (default_renderer_ == RENDER_IN_HOST) ?
+ *default_renderer = static_cast<RendererForUrl>(value);
+ const char* exclusion_list_name = (*default_renderer == RENDER_IN_HOST) ?
policy::key::kRenderInChromeFrameList :
policy::key::kRenderInHostList;
EnumerateKeyValues(config_key.Handle(),
- ASCIIToWide(exclusion_list_name).c_str(), &renderer_exclusion_list_);
+ ASCIIToWide(exclusion_list_name).c_str(), renderer_exclusion_list);
DVLOG(1) << "Default renderer as specified via policy: "
- << default_renderer_
- << " exclusion list size: " << renderer_exclusion_list_.size();
+ << *default_renderer
+ << " exclusion list size: " << renderer_exclusion_list->size();
}
+}
+
+// static
+void PolicySettings::ReadContentTypeSetting(
+ std::vector<std::wstring>* content_type_list) {
+ DCHECK(content_type_list);
std::wstring sub_key(policy::kRegistrySubKey);
sub_key += L"\\";
sub_key += ASCIIToWide(policy::key::kChromeFrameContentTypes);
- for (int i = 0; i < arraysize(root_key) && content_type_list_.size() == 0;
+ content_type_list->clear();
+ for (int i = 0; i < arraysize(kRootKeys) && content_type_list->size() == 0;
++i) {
- EnumerateKeyValues(root_key[i], sub_key.c_str(), &content_type_list_);
+ EnumerateKeyValues(kRootKeys[i], sub_key.c_str(), content_type_list);
}
}
+// static
+void PolicySettings::ReadApplicationLocaleSetting(
+ std::wstring* application_locale) {
+ DCHECK(application_locale);
+
+ application_locale->clear();
+ base::win::RegKey config_key;
+ std::wstring application_locale_value(
+ ASCIIToWide(policy::key::kApplicationLocaleValue));
+ for (int i = 0; i < arraysize(kRootKeys); ++i) {
+ if (config_key.Open(kRootKeys[i], policy::kRegistrySubKey, KEY_READ) &&
+ config_key.ReadValue(application_locale_value.c_str(),
+ application_locale)) {
+ break;
+ }
+ }
+}
+
+void PolicySettings::RefreshFromRegistry() {
+ RendererForUrl default_renderer;
+ std::vector<std::wstring> renderer_exclusion_list;
+ std::vector<std::wstring> content_type_list;
+ std::wstring application_locale;
+
+ // Read the latest settings from the registry
+ ReadUrlSettings(&default_renderer, &renderer_exclusion_list);
+ ReadContentTypeSetting(&content_type_list);
+ ReadApplicationLocaleSetting(&application_locale);
+
+ // Nofail swap in the new values. (Note: this is all that need be protected
+ // under a mutex if/when this becomes thread safe.)
+ using std::swap;
+
+ swap(default_renderer_, default_renderer);
+ swap(renderer_exclusion_list_, renderer_exclusion_list);
+ swap(content_type_list_, content_type_list);
+ swap(application_locale_, application_locale);
+}
+
diff --git a/chrome_frame/policy_settings.h b/chrome_frame/policy_settings.h
index f3eacac..28182bd 100644
--- a/chrome_frame/policy_settings.h
+++ b/chrome_frame/policy_settings.h
@@ -8,6 +8,8 @@
#include <string>
#include <vector>
+#include "base/basictypes.h"
+
// A simple class that reads and caches policy settings for Chrome Frame.
// TODO(tommi): Support refreshing when new settings are pushed.
// TODO(tommi): Use Chrome's classes for this (and the notification service).
@@ -34,6 +36,19 @@ class PolicySettings {
RendererForUrl GetRendererForContentType(const wchar_t* content_type);
+ // Returns the policy-configured Chrome app locale, or an empty string if none
+ // is configured.
+ const std::wstring& ApplicationLocale() const {
+ return application_locale_;
+ }
+
+ // Helper functions for reading settings from the registry
+ static void ReadUrlSettings(RendererForUrl* default_renderer,
+ std::vector<std::wstring>* renderer_exclusion_list);
+ static void ReadContentTypeSetting(
+ std::vector<std::wstring>* content_type_list);
+ static void ReadApplicationLocaleSetting(std::wstring* application_locale);
+
protected:
// Protected for now since the class is not thread safe.
void RefreshFromRegistry();
@@ -42,6 +57,10 @@ class PolicySettings {
RendererForUrl default_renderer_;
std::vector<std::wstring> renderer_exclusion_list_;
std::vector<std::wstring> content_type_list_;
+ std::wstring application_locale_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PolicySettings);
};
diff --git a/chrome_frame/simple_resource_loader.cc b/chrome_frame/simple_resource_loader.cc
index e39087c..844afa7 100644
--- a/chrome_frame/simple_resource_loader.cc
+++ b/chrome_frame/simple_resource_loader.cc
@@ -4,40 +4,174 @@
#include "chrome_frame/simple_resource_loader.h"
+#include <algorithm>
+
#include <atlbase.h>
-#include <string>
#include "base/base_paths.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/path_service.h"
+#include "base/i18n/file_util_icu.h"
#include "base/i18n/rtl.h"
+#include "base/singleton.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "base/win/windows_version.h"
+#include "chrome_frame/policy_settings.h"
+
+namespace {
+
const wchar_t kLocalesDirName[] = L"Locales";
-HINSTANCE SimpleResourceLoader::locale_dll_handle_;
+bool IsInvalidTagCharacter(wchar_t tag_character) {
+ return !(L'-' == tag_character ||
+ IsAsciiDigit(tag_character) ||
+ IsAsciiAlpha(tag_character));
+}
+
+// A helper function object that performs a lower-case ASCII comparison between
+// two strings.
+class CompareInsensitiveASCII
+ : public std::unary_function<const std::wstring&, bool> {
+ public:
+ explicit CompareInsensitiveASCII(const std::wstring& value)
+ : value_lowered_(WideToASCII(value)) {
+ StringToLowerASCII(&value_lowered_);
+ }
+ bool operator()(const std::wstring& comparand) {
+ return LowerCaseEqualsASCII(comparand, value_lowered_.c_str());
+ }
+
+ private:
+ std::string value_lowered_;
+};
+
+// Returns true if the value was added.
+bool PushBackIfAbsent(
+ const std::wstring& value,
+ std::vector<std::wstring>* collection) {
+ if (collection->end() ==
+ std::find_if(collection->begin(), collection->end(),
+ CompareInsensitiveASCII(value))) {
+ collection->push_back(value);
+ return true;
+ }
+ return false;
+}
+
+} // namespace
-SimpleResourceLoader::SimpleResourceLoader() {
+SimpleResourceLoader::SimpleResourceLoader()
+ : locale_dll_handle_(NULL) {
// Find and load the resource DLL.
+ std::vector<std::wstring> language_tags;
+
+ // First, try the locale dictated by policy and its fallback.
+ std::wstring application_locale =
+ Singleton<PolicySettings>()->ApplicationLocale();
+ if (!application_locale.empty()) {
+ language_tags.push_back(application_locale);
+ std::wstring::size_type dash = application_locale.find(L'-');
+ if (std::wstring::npos != dash) {
+ if (0 != dash) {
+ language_tags.push_back(application_locale.substr(0, dash));
+ } else {
+ NOTREACHED() << "Group Policy application locale begins with a dash.";
+ }
+ }
+ }
+
+ // Next, try the thread, process, user, system languages.
+ GetPreferredLanguages(&language_tags);
+
+ // Finally, fall-back on "en-US" (which may already be present in the vector,
+ // but that's okay since we'll exit with success when the first is tried).
+ language_tags.push_back(L"en-US");
+
+ FilePath locales_path;
+ FilePath locale_dll_path;
+
+ DetermineLocalesDirectory(&locales_path);
+ if (LoadLocaleDll(language_tags, locales_path, &locale_dll_handle_,
+ &locale_dll_path)) {
+ language_ = locale_dll_path.BaseName().RemoveExtension().value();
+ } else {
+ NOTREACHED() << "Failed loading any resource dll (even \"en-US\").";
+ }
+}
+
+SimpleResourceLoader::~SimpleResourceLoader() {
+ locale_dll_handle_ = NULL;
+}
+
+// static
+void SimpleResourceLoader::GetPreferredLanguages(
+ std::vector<std::wstring>* language_tags) {
+ // The full set of preferred languages and their fallbacks are given priority.
+ GetThreadPreferredUILanguages(language_tags);
+
+ // The above gives us nothing pre-Vista, so use ICU to get the system
+ // language and add it and its fallback to the end of the list if not present.
std::wstring language;
std::wstring region;
- GetSystemLocale(&language, &region);
- FilePath locale_dll_path;
- if (GetLocaleFilePath(language, region, &locale_dll_path)) {
- DCHECK(locale_dll_handle_ == NULL) << "Locale DLL is already loaded!";
- locale_dll_handle_ = LoadLocaleDll(locale_dll_path);
- DCHECK(locale_dll_handle_ != NULL) << "Failed to load locale dll!";
+ GetICUSystemLanguage(&language, &region);
+ if (!region.empty()) {
+ std::wstring combined;
+ combined.reserve(language.size() + 1 + region.size());
+ combined.assign(language).append(L"-").append(region);
+ PushBackIfAbsent(combined, language_tags);
}
+ PushBackIfAbsent(language, language_tags);
}
-SimpleResourceLoader::~SimpleResourceLoader() {}
+// static
+bool SimpleResourceLoader::GetThreadPreferredUILanguages(
+ std::vector<std::wstring>* language_tags) {
+ typedef BOOL (WINAPI* GetThreadPreferredUILanguages_Fn)(
+ DWORD, PULONG, PZZWSTR, PULONG);
+ HMODULE kernel32 = GetModuleHandle(L"kernel32.dll");
+ DCHECK(kernel32) << "Failed finding kernel32.dll!";
+ GetThreadPreferredUILanguages_Fn get_thread_preferred_ui_languages =
+ reinterpret_cast<GetThreadPreferredUILanguages_Fn>(
+ GetProcAddress(kernel32, "GetThreadPreferredUILanguages"));
+ bool have_mui = (NULL != get_thread_preferred_ui_languages);
+ if (have_mui) {
+ const DWORD kNameAndFallbackFlags =
+ MUI_LANGUAGE_NAME | MUI_MERGE_SYSTEM_FALLBACK | MUI_MERGE_USER_FALLBACK;
+ ULONG language_count = 0;
+ ULONG buffer_length = 0;
+
+ if (get_thread_preferred_ui_languages(
+ kNameAndFallbackFlags,
+ &language_count,
+ NULL,
+ &buffer_length) && 0 != buffer_length) {
+ std::vector<wchar_t> language_names(buffer_length);
+
+ if (get_thread_preferred_ui_languages(
+ kNameAndFallbackFlags,
+ &language_count,
+ &language_names[0],
+ &buffer_length)) {
+ std::vector<wchar_t>::const_iterator scan = language_names.begin();
+ std::wstring language(&*scan);
+ while (!language.empty()) {
+ language_tags->push_back(language);
+ scan += language.size() + 1;
+ language.assign(&*scan);
+ }
+ }
+ }
+ }
+ return have_mui;
+}
-void SimpleResourceLoader::GetSystemLocale(std::wstring* language,
- std::wstring* region) {
+// static
+void SimpleResourceLoader::GetICUSystemLanguage(std::wstring* language,
+ std::wstring* region) {
DCHECK(language);
DCHECK(region);
@@ -45,89 +179,90 @@ void SimpleResourceLoader::GetSystemLocale(std::wstring* language,
base::i18n::GetLanguageAndRegionFromOS(&icu_language, &icu_region);
if (!icu_language.empty()) {
*language = ASCIIToWide(icu_language);
+ } else {
+ language->clear();
}
if (!icu_region.empty()) {
*region = ASCIIToWide(icu_region);
+ } else {
+ region->clear();
}
}
-bool SimpleResourceLoader::GetLocaleFilePath(const std::wstring& language,
- const std::wstring& region,
- FilePath* file_path) {
- DCHECK(file_path);
+// static
+void SimpleResourceLoader::DetermineLocalesDirectory(FilePath* locales_path) {
+ DCHECK(locales_path);
FilePath module_path;
PathService::Get(base::DIR_MODULE, &module_path);
- FilePath locales_path = module_path.Append(kLocalesDirName);
+ *locales_path = module_path.Append(kLocalesDirName);
// We may be residing in the "locales" directory's parent, or we might be
// in a sibling directory. Move up one and look for Locales again in the
// latter case.
- if (!file_util::DirectoryExists(locales_path)) {
- locales_path = module_path.DirName();
- locales_path = locales_path.Append(kLocalesDirName);
+ if (!file_util::DirectoryExists(*locales_path)) {
+ *locales_path = module_path.DirName();
+ *locales_path = locales_path->Append(kLocalesDirName);
}
- bool found_dll = false;
- if (file_util::DirectoryExists(locales_path)) {
- std::wstring dll_name(language);
- FilePath look_path;
-
- // First look for the [language]-[region].DLL.
- if (!region.empty()) {
- dll_name += L"-";
- dll_name += region;
- dll_name += L".dll";
-
- look_path = locales_path.Append(dll_name);
- if (file_util::PathExists(look_path)) {
- *file_path = look_path;
- found_dll = true;
- }
- }
-
- // Next look for just [language].DLL.
- if (!found_dll) {
- dll_name = language;
- dll_name += L".dll";
- look_path = locales_path.Append(dll_name);
- if (file_util::PathExists(look_path)) {
- *file_path = look_path;
- found_dll = true;
- }
- }
-
- // Finally, try defaulting to en-US.dll.
- if (!found_dll) {
- look_path = locales_path.Append(L"en-US.dll");
- if (file_util::PathExists(look_path)) {
- *file_path = look_path;
- found_dll = true;
- }
- }
- } else {
- NOTREACHED() << "Could not locate locales DLL directory.";
- }
+ // Don't make a second check to see if the dir is in the parent. We'll notice
+ // and log that in LoadLocaleDll when we actually try loading DLLs.
+}
- return found_dll;
+// static
+bool SimpleResourceLoader::IsValidLanguageTag(
+ const std::wstring& language_tag) {
+ // "[a-zA-Z]+(-[a-zA-Z0-9]+)*" is a simplification, but better than nothing.
+ // Rather than pick up the weight of a regex processor, just search for a
+ // character that isn't in the above set. This will at least weed out
+ // attempts at "../../EvilBinary".
+ return language_tag.end() == std::find_if(language_tag.begin(),
+ language_tag.end(),
+ &IsInvalidTagCharacter);
}
-HINSTANCE SimpleResourceLoader::LoadLocaleDll(const FilePath& dll_path) {
- DWORD load_flags = 0;
- if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
- load_flags = LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE |
- LOAD_LIBRARY_AS_IMAGE_RESOURCE;
- } else {
- load_flags = DONT_RESOLVE_DLL_REFERENCES;
- }
+// static
+bool SimpleResourceLoader::LoadLocaleDll(
+ const std::vector<std::wstring>& language_tags,
+ const FilePath& locales_path,
+ HMODULE* dll_handle,
+ FilePath* file_path) {
+ DCHECK(file_path);
// The dll should only have resources, not executable code.
- HINSTANCE locale_dll_handle = LoadLibraryEx(dll_path.value().c_str(), NULL,
+ const DWORD load_flags =
+ (base::win::GetVersion() >= base::win::VERSION_VISTA ?
+ LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE | LOAD_LIBRARY_AS_IMAGE_RESOURCE :
+ DONT_RESOLVE_DLL_REFERENCES);
+ const std::wstring dll_suffix(L".dll");
+ bool found_dll = false;
+
+ for (std::vector<std::wstring>::const_iterator scan = language_tags.begin(),
+ end = language_tags.end();
+ scan != end;
+ ++scan) {
+ if (!IsValidLanguageTag(*scan)) {
+ LOG(WARNING) << "Invalid language tag supplied while locating resources:"
+ " \"" << *scan << "\"";
+ continue;
+ }
+ FilePath look_path = locales_path.Append(*scan + dll_suffix);
+ HMODULE locale_dll_handle = LoadLibraryEx(look_path.value().c_str(), NULL,
load_flags);
- DCHECK(locale_dll_handle != NULL) << "unable to load generated resources: "
- << GetLastError();
+ if (NULL != locale_dll_handle) {
+ *dll_handle = locale_dll_handle;
+ *file_path = look_path;
+ found_dll = true;
+ break;
+ }
+ DPCHECK(ERROR_FILE_NOT_FOUND == GetLastError())
+ << "Unable to load generated resources from " << look_path.value();
+ }
+
+ DCHECK(found_dll || file_util::DirectoryExists(locales_path))
+ << "Could not locate locales DLL directory.";
- return locale_dll_handle;
+ return found_dll;
}
std::wstring SimpleResourceLoader::GetLocalizedResource(int message_id) {
@@ -154,11 +289,16 @@ std::wstring SimpleResourceLoader::GetLocalizedResource(int message_id) {
}
// static
+std::wstring SimpleResourceLoader::GetLanguage() {
+ return SimpleResourceLoader::instance()->language_;
+}
+
+// static
std::wstring SimpleResourceLoader::Get(int message_id) {
SimpleResourceLoader* loader = SimpleResourceLoader::instance();
return loader->GetLocalizedResource(message_id);
}
-HINSTANCE SimpleResourceLoader::GetResourceModuleHandle() {
+HMODULE SimpleResourceLoader::GetResourceModuleHandle() {
return locale_dll_handle_;
}
diff --git a/chrome_frame/simple_resource_loader.h b/chrome_frame/simple_resource_loader.h
index 45aca746..9f10934 100644
--- a/chrome_frame/simple_resource_loader.h
+++ b/chrome_frame/simple_resource_loader.h
@@ -12,6 +12,7 @@
#include <windows.h>
#include <string>
+#include <vector>
#include "base/file_path.h"
#include "base/gtest_prod_util.h"
@@ -24,33 +25,50 @@ class SimpleResourceLoader {
return Singleton<SimpleResourceLoader>::get();
}
+ // Returns the language tag for the active language.
+ static std::wstring GetLanguage();
+
// Helper method to return the string resource identified by message_id
// from the currently loaded locale dll.
static std::wstring Get(int message_id);
// Retrieves the HINSTANCE of the loaded module handle. May be NULL if a
// resource DLL could not be loaded.
- HINSTANCE GetResourceModuleHandle();
+ HMODULE GetResourceModuleHandle();
+
+ // Retrieves the preferred languages for the current thread, adding them to
+ // |language_tags|.
+ static void GetPreferredLanguages(std::vector<std::wstring>* language_tags);
+
+ // Retrieves the thread/process/user/system preferred languages on Vista+,
+ // adding them and their fallbacks to |language_tags|. Returns |false| if the
+ // platform does not support such (i.e., XP).
+ static bool GetThreadPreferredUILanguages(
+ std::vector<std::wstring>* language_tags);
+
+ // Retrieves the system language and the region using ICU (used on XP).
+ static void GetICUSystemLanguage(std::wstring* language,
+ std::wstring* region);
+
+ // Populates |locales_path| with the path to the "Locales" directory.
+ static void DetermineLocalesDirectory(FilePath* locales_path);
+
+ // Returns false if |language_tag| is malformed.
+ static bool IsValidLanguageTag(const std::wstring& language_tag);
private:
SimpleResourceLoader();
~SimpleResourceLoader();
- // Retrieves the system language and the region using ICU.
- void GetSystemLocale(std::wstring* language, std::wstring* region);
-
- // Uses |locale| to build the resource DLL name and then looks for the named
- // DLL in known locales paths. If it doesn't find it, it falls back to
- // looking for an en-US.dll.
+ // Finds the most-preferred resource DLL for the laguages in |language_tags|
+ // in |locales_path|.
//
- // Returns true if a locale DLL can be found, false otherwise.
- bool GetLocaleFilePath(const std::wstring& language,
- const std::wstring& region,
- FilePath* file_path);
-
- // Loads the locale dll at the given path. Returns a handle to the DLL or
- // NULL on failure.
- HINSTANCE LoadLocaleDll(const FilePath& dll_path);
+ // Returns true on success with a handle to the DLL that was loaded in
+ // |dll_handle| and its path in |file_path|.
+ static bool LoadLocaleDll(const std::vector<std::wstring>& language_tags,
+ const FilePath& locales_path,
+ HMODULE* dll_handle,
+ FilePath* file_path);
// Returns the string resource identified by message_id from the currently
// loaded locale dll.
@@ -58,9 +76,10 @@ class SimpleResourceLoader {
friend struct DefaultSingletonTraits<SimpleResourceLoader>;
- FRIEND_TEST_ALL_PREFIXES(SimpleResourceLoaderTest, GetLocaleFilePath);
+ FRIEND_TEST_ALL_PREFIXES(SimpleResourceLoaderTest, LoadLocaleDll);
- static HINSTANCE locale_dll_handle_;
+ std::wstring language_;
+ HINSTANCE locale_dll_handle_;
};
#endif // CHROME_FRAME_SIMPLE_RESOURCE_LOADER_H_
diff --git a/chrome_frame/test/automation_client_mock.cc b/chrome_frame/test/automation_client_mock.cc
index 7626c0b..a77b023 100644
--- a/chrome_frame/test/automation_client_mock.cc
+++ b/chrome_frame/test/automation_client_mock.cc
@@ -104,7 +104,7 @@ TEST(CFACWithChrome, CreateTooFast) {
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path, profile_path.BaseName().value(), L"",
+ empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
@@ -136,7 +136,7 @@ TEST(CFACWithChrome, CreateNotSoFast) {
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path, profile_path.BaseName().value(), L"",
+ empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
@@ -182,7 +182,7 @@ TEST(CFACWithChrome, NavigateOk) {
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path, profile_path.BaseName().value(), L"",
+ empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
@@ -228,7 +228,7 @@ TEST(CFACWithChrome, NavigateFailed) {
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path, profile_path.BaseName().value(), L"",
+ empty, empty, profile_path, profile_path.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(10000);
clp->set_version_check(false);
@@ -266,7 +266,7 @@ TEST_F(CFACMockTest, MockedCreateTabOk) {
// Here we go!
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path_, profile_path_.BaseName().value(), L"",
+ empty, empty, profile_path_, profile_path_.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout);
clp->set_version_check(false);
@@ -298,7 +298,7 @@ TEST_F(CFACMockTest, MockedCreateTabFailed) {
// Here we go!
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path_, profile_path_.BaseName().value(), L"",
+ empty, empty, profile_path_, profile_path_.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(timeout_);
clp->set_version_check(false);
@@ -338,7 +338,7 @@ TEST_F(CFACMockTest, OnChannelError) {
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(new ChromeFrameLaunchParams(
- empty, empty, profile_path_, profile_path_.BaseName().value(), L"",
+ empty, empty, profile_path_, profile_path_.BaseName().value(), L"", L"",
false, false, false));
clp->set_launch_timeout(1); // Unneeded timeout, but can't be 0.
clp->set_version_check(false);
@@ -457,7 +457,7 @@ TEST_F(CFACMockTest, NavigateTwiceAfterInitToSameUrl) {
scoped_refptr<ChromeFrameLaunchParams> launch_params(
new ChromeFrameLaunchParams(
GURL("http://www.nonexistent.com"), empty, profile_path_,
- profile_path_.BaseName().value(), L"", false, false, false));
+ profile_path_.BaseName().value(), L"", L"", false, false, false));
launch_params->set_launch_timeout(timeout);
launch_params->set_version_check(false);
EXPECT_TRUE(client_->Initialize(&cfd_, launch_params));
diff --git a/chrome_frame/test/chrome_frame_automation_mock.h b/chrome_frame/test/chrome_frame_automation_mock.h
index 2d7a76e..0887f81 100644
--- a/chrome_frame/test/chrome_frame_automation_mock.h
+++ b/chrome_frame/test/chrome_frame_automation_mock.h
@@ -24,6 +24,7 @@ class AutomationMockDelegate
AutomationMockDelegate(MessageLoop* caller_message_loop,
int launch_timeout, bool perform_version_check,
const std::wstring& profile_name,
+ const std::wstring& language,
const std::wstring& extra_chrome_arguments, bool incognito,
bool is_widget_mode)
: caller_message_loop_(caller_message_loop), is_connected_(false),
@@ -40,7 +41,8 @@ class AutomationMockDelegate
GURL empty;
scoped_refptr<ChromeFrameLaunchParams> clp(
new ChromeFrameLaunchParams(empty, empty, profile_path, profile_name,
- extra_chrome_arguments, incognito, is_widget_mode, false));
+ language, extra_chrome_arguments, incognito, is_widget_mode,
+ false));
clp->set_launch_timeout(launch_timeout);
clp->set_version_check(perform_version_check);
automation_client_->Initialize(this, clp);
@@ -145,7 +147,7 @@ class AutomationMockLaunch
typedef AutomationMockDelegate<AutomationMockLaunch> Base;
AutomationMockLaunch(MessageLoop* caller_message_loop,
int launch_timeout)
- : Base(caller_message_loop, launch_timeout, true, L"", L"", false,
+ : Base(caller_message_loop, launch_timeout, true, L"", L"", L"", false,
false) {
}
virtual void OnAutomationServerReady() {
@@ -163,7 +165,7 @@ class AutomationMockNavigate
typedef AutomationMockDelegate<AutomationMockNavigate> Base;
AutomationMockNavigate(MessageLoop* caller_message_loop,
int launch_timeout)
- : Base(caller_message_loop, launch_timeout, true, L"", L"", false,
+ : Base(caller_message_loop, launch_timeout, true, L"", L"", L"", false,
false) {
}
virtual void OnLoad(int tab_handle, const GURL& url) {
@@ -178,7 +180,8 @@ class AutomationMockPostMessage
typedef AutomationMockDelegate<AutomationMockPostMessage> Base;
AutomationMockPostMessage(MessageLoop* caller_message_loop,
int launch_timeout)
- : Base(caller_message_loop, launch_timeout, true, L"", L"", false, false),
+ : Base(caller_message_loop, launch_timeout, true, L"", L"", L"", false,
+ false),
postmessage_result_(false) {}
bool postmessage_result() const {
return postmessage_result_;
@@ -206,7 +209,8 @@ class AutomationMockHostNetworkRequestStart
typedef AutomationMockDelegate<AutomationMockHostNetworkRequestStart> Base;
AutomationMockHostNetworkRequestStart(MessageLoop* caller_message_loop,
int launch_timeout)
- : Base(caller_message_loop, launch_timeout, true, L"", L"", false, false),
+ : Base(caller_message_loop, launch_timeout, true, L"", L"", L"", false,
+ false),
request_start_result_(false) {
if (automation()) {
automation()->set_use_chrome_network(false);
diff --git a/chrome_frame/test/policy_settings_unittest.cc b/chrome_frame/test/policy_settings_unittest.cc
index 52a3c55..55a0b32 100644
--- a/chrome_frame/test/policy_settings_unittest.cc
+++ b/chrome_frame/test/policy_settings_unittest.cc
@@ -25,6 +25,7 @@ void DeleteChromeFramePolicyEntries(HKEY root) {
key.DeleteKey(ASCIIToWide(policy::key::kRenderInChromeFrameList).c_str());
key.DeleteKey(ASCIIToWide(policy::key::kRenderInHostList).c_str());
key.DeleteKey(ASCIIToWide(policy::key::kChromeFrameContentTypes).c_str());
+ key.DeleteKey(ASCIIToWide(policy::key::kApplicationLocaleValue).c_str());
}
}
@@ -118,6 +119,17 @@ bool SetCFContentTypes(HKEY policy_root, const wchar_t* content_types[],
return true;
}
+bool SetChromeApplicationLocale(HKEY policy_root, const wchar_t* locale) {
+ RegKey policy_key;
+ if (!InitializePolicyKey(policy_root, &policy_key))
+ return false;
+
+ std::wstring application_locale_value(
+ ASCIIToWide(policy::key::kApplicationLocaleValue));
+ EXPECT_TRUE(policy_key.WriteValue(application_locale_value.c_str(), locale));
+ return true;
+}
+
} // end namespace
TEST(PolicySettings, RendererForUrl) {
@@ -215,3 +227,26 @@ TEST(PolicySettings, RendererForContentType) {
}
}
+TEST(PolicySettings, ApplicationLocale) {
+ TempRegKeyOverride::DeleteAllTempKeys();
+
+ scoped_ptr<TempRegKeyOverride> hklm_pol(
+ new TempRegKeyOverride(HKEY_LOCAL_MACHINE, L"hklm_pol"));
+ scoped_ptr<TempRegKeyOverride> hkcu_pol(
+ new TempRegKeyOverride(HKEY_CURRENT_USER, L"hkcu_pol"));
+
+ scoped_ptr<PolicySettings> settings(new PolicySettings());
+ EXPECT_TRUE(settings->ApplicationLocale().empty());
+
+ static const wchar_t kTestApplicationLocale[] = L"fr-CA";
+
+ HKEY root[] = { HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER };
+ for (int i = 0; i < arraysize(root); ++i) {
+ SetChromeApplicationLocale(root[i], kTestApplicationLocale);
+ settings.reset(new PolicySettings());
+ EXPECT_EQ(std::wstring(kTestApplicationLocale),
+ settings->ApplicationLocale());
+
+ DeleteChromeFramePolicyEntries(root[i]);
+ }
+}
diff --git a/chrome_frame/test/proxy_factory_mock.cc b/chrome_frame/test/proxy_factory_mock.cc
index 6e15104..effc4a0 100644
--- a/chrome_frame/test/proxy_factory_mock.cc
+++ b/chrome_frame/test/proxy_factory_mock.cc
@@ -21,7 +21,7 @@ TEST(ProxyFactoryTest, CreateDestroy) {
FilePath profile_path;
scoped_refptr<ChromeFrameLaunchParams> params(
new ChromeFrameLaunchParams(empty, empty, profile_path,
- L"Adam.N.Epilinter", L"", false, false, false));
+ L"Adam.N.Epilinter", L"", L"", false, false, false));
params->set_launch_timeout(0);
params->set_version_check(false);
@@ -41,7 +41,7 @@ TEST(ProxyFactoryTest, CreateSameProfile) {
FilePath profile_path;
scoped_refptr<ChromeFrameLaunchParams> params(
new ChromeFrameLaunchParams(empty, empty, profile_path,
- L"Dr. Gratiano Forbeson", L"", false, false, false));
+ L"Dr. Gratiano Forbeson", L"", L"", false, false, false));
params->set_launch_timeout(0);
params->set_version_check(false);
@@ -65,13 +65,13 @@ TEST(ProxyFactoryTest, CreateDifferentProfiles) {
FilePath profile_path;
scoped_refptr<ChromeFrameLaunchParams> params1(
new ChromeFrameLaunchParams(empty, empty, profile_path,
- L"Adam.N.Epilinter", L"", false, false, false));
+ L"Adam.N.Epilinter", L"", L"", false, false, false));
params1->set_launch_timeout(0);
params1->set_version_check(false);
scoped_refptr<ChromeFrameLaunchParams> params2(
new ChromeFrameLaunchParams(empty, empty, profile_path,
- L"Dr. Gratiano Forbeson", L"", false, false, false));
+ L"Dr. Gratiano Forbeson", L"", L"", false, false, false));
params2->set_launch_timeout(0);
params2->set_version_check(false);
@@ -95,7 +95,7 @@ TEST(ProxyFactoryTest, FastCreateDestroy) {
FilePath profile_path;
scoped_refptr<ChromeFrameLaunchParams> params(
new ChromeFrameLaunchParams(empty, empty, profile_path,
- L"Dr. Gratiano Forbeson", L"", false, false, false));
+ L"Dr. Gratiano Forbeson", L"", L"", false, false, false));
params->set_launch_timeout(10000);
params->set_version_check(false);
diff --git a/chrome_frame/test/simple_resource_loader_test.cc b/chrome_frame/test/simple_resource_loader_test.cc
index f67ef49..e120a6b 100644
--- a/chrome_frame/test/simple_resource_loader_test.cc
+++ b/chrome_frame/test/simple_resource_loader_test.cc
@@ -5,21 +5,83 @@
#include "chrome_frame/simple_resource_loader.h"
#include "base/file_path.h"
+#include "base/win/windows_version.h"
#include "testing/gtest/include/gtest/gtest.h"
-TEST(SimpleResourceLoaderTest, GetLocaleFilePath) {
- SimpleResourceLoader loader;
-
+TEST(SimpleResourceLoaderTest, LoadLocaleDll) {
+ std::vector<std::wstring> language_tags;
+ FilePath locales_path;
FilePath file_path;
+ HMODULE dll_handle = NULL;
+
+ SimpleResourceLoader::DetermineLocalesDirectory(&locales_path);
+
// Test valid language-region string:
- EXPECT_TRUE(loader.GetLocaleFilePath(L"en", L"GB", &file_path));
+ language_tags.clear();
+ language_tags.push_back(L"en-GB");
+ language_tags.push_back(L"en");
+ EXPECT_TRUE(
+ SimpleResourceLoader::LoadLocaleDll(language_tags, locales_path,
+ &dll_handle, &file_path));
+ if (NULL != dll_handle) {
+ FreeLibrary(dll_handle);
+ dll_handle = NULL;
+ }
EXPECT_TRUE(file_path.BaseName() == FilePath(L"en-GB.dll"));
// Test valid language-region string for which we only have a language dll:
- EXPECT_TRUE(loader.GetLocaleFilePath(L"fr", L"FR", &file_path));
+ language_tags.clear();
+ language_tags.push_back(L"fr-FR");
+ language_tags.push_back(L"fr");
+ EXPECT_TRUE(
+ SimpleResourceLoader::LoadLocaleDll(language_tags, locales_path,
+ &dll_handle, &file_path));
+ if (NULL != dll_handle) {
+ FreeLibrary(dll_handle);
+ dll_handle = NULL;
+ }
EXPECT_TRUE(file_path.BaseName() == FilePath(L"fr.dll"));
- // Test invalid language-region string, make sure defaults to en-US.dll:
- EXPECT_TRUE(loader.GetLocaleFilePath(L"xx", L"XX", &file_path));
+ // Test invalid language-region string, make sure fallback works:
+ language_tags.clear();
+ language_tags.push_back(L"xx-XX");
+ language_tags.push_back(L"en-US");
+ EXPECT_TRUE(
+ SimpleResourceLoader::LoadLocaleDll(language_tags, locales_path,
+ &dll_handle, &file_path));
+ if (NULL != dll_handle) {
+ FreeLibrary(dll_handle);
+ dll_handle = NULL;
+ }
EXPECT_TRUE(file_path.BaseName() == FilePath(L"en-US.dll"));
}
+
+TEST(SimpleResourceLoaderTest, GetThreadPreferredUILanguages) {
+ std::vector<std::wstring> language_tags;
+
+ if (base::win::GetVersion() >= base::win::VERSION_VISTA) {
+ EXPECT_TRUE(
+ SimpleResourceLoader::GetThreadPreferredUILanguages(&language_tags));
+ // Did we find at least one language?
+ EXPECT_NE(static_cast<std::vector<std::wstring>::size_type>(0),
+ language_tags.size());
+ } else {
+ EXPECT_FALSE(
+ SimpleResourceLoader::GetThreadPreferredUILanguages(&language_tags));
+ }
+}
+
+TEST(SimpleResourceLoaderTest, GetICUSystemLanguage) {
+ std::wstring language;
+ std::wstring region;
+
+ SimpleResourceLoader::GetICUSystemLanguage(&language, &region);
+ EXPECT_NE(static_cast<std::wstring::size_type>(0), language.size());
+}
+
+TEST(SimpleResourceLoaderTest, InstanceTest) {
+ SimpleResourceLoader* loader = SimpleResourceLoader::instance();
+
+ ASSERT_TRUE(NULL != loader);
+ ASSERT_TRUE(NULL != loader->GetResourceModuleHandle());
+}