summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Varga <pvarga@inf.u-szeged.hu>2016-05-24 17:08:09 +0200
committerPeter Varga <pvarga@inf.u-szeged.hu>2016-07-13 21:12:03 +0000
commit89319455c36d48fe46a8501edd3c174c1de291fb (patch)
tree8ba7c33284a0b973090eb5de322ef466a859fbcf
parent9bb9076c50048913075f11692f784ebb959d63cf (diff)
Fix changing locale of ResourceBundle on Linux
The ResourceBundle is not re-initialized for new Renderer Processes because it is initialized only once in Zygote Process. This means runtime locale changes do not affect new Renderer Processes. Zygote Process is supported on Linux only thus other platforms don't need this fix. With this change the locale of the ResourceBundle is reloaded when new Renderer Process is started. For accessing the pak file of the locale in the sandboxed environment the file descriptor is passed via the Chromium's GlobalDescriptor solution. Task-number: QTBUG-53000 Change-Id: I57e84078db9d0795d16d930aa1b3e93a6e86ec39 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
m---------src/3rdparty0
-rw-r--r--src/core/content_browser_client_qt.cpp21
-rw-r--r--src/core/content_browser_client_qt.h4
-rw-r--r--src/core/content_main_delegate_qt.cpp13
-rw-r--r--src/core/core_gyp_generator.pro1
-rw-r--r--src/core/global_descriptors_qt.h10
-rw-r--r--src/core/resource_bundle_qt.cpp68
-rw-r--r--src/core/web_engine_library_info.cpp12
-rw-r--r--tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp37
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp32
10 files changed, 195 insertions, 3 deletions
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 428ec4b558454d610b9cfbd6735a90157562831
+Subproject b5d5ca440f575fdc81ca95b9ba8c4c8f4ff5818
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 8da5e2611..0c3acd37b 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -85,6 +85,11 @@
#include "web_engine_context.h"
#include "web_engine_library_info.h"
+#if defined(Q_OS_LINUX)
+#include "global_descriptors_qt.h"
+#include "ui/base/resource/resource_bundle.h"
+#endif
+
#if defined(ENABLE_PLUGINS)
#include "content/public/browser/browser_ppapi_host.h"
#include "ppapi/host/ppapi_host.h"
@@ -457,6 +462,22 @@ void ContentBrowserClientQt::AppendExtraCommandLineSwitches(base::CommandLine* c
command_line->AppendSwitchASCII(switches::kLang, GetApplicationLocale());
}
+#if defined(Q_OS_LINUX)
+void ContentBrowserClientQt::GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings)
+{
+ const std::string &locale = GetApplicationLocale();
+ const base::FilePath &locale_file_path = ui::ResourceBundle::GetSharedInstance().GetLocaleFilePath(locale, true);
+ if (locale_file_path.empty())
+ return;
+
+ // Open pak file of the current locale in the Browser process and pass its file descriptor to the sandboxed
+ // Renderer Process. FileDescriptorInfo is responsible for closing the file descriptor.
+ int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
+ base::File locale_file = base::File(locale_file_path, flags);
+ mappings->Transfer(kWebEngineLocale, base::ScopedFD(locale_file.TakePlatformFile()));
+}
+#endif
+
#if defined(ENABLE_PLUGINS)
void ContentBrowserClientQt::DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) {
browser_host->GetPpapiHost()->AddHostFactoryFilter(
diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h
index 58924eb30..098631476 100644
--- a/src/core/content_browser_client_qt.h
+++ b/src/core/content_browser_client_qt.h
@@ -109,6 +109,10 @@ public:
std::string GetAcceptLangs(content::BrowserContext* context) Q_DECL_OVERRIDE;
virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) Q_DECL_OVERRIDE;
+#if defined(Q_OS_LINUX)
+ virtual void GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::FileDescriptorInfo* mappings) Q_DECL_OVERRIDE;
+#endif
+
#if defined(ENABLE_PLUGINS)
virtual void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) Q_DECL_OVERRIDE;
#endif
diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp
index a9c49ff2e..379c42468 100644
--- a/src/core/content_main_delegate_qt.cpp
+++ b/src/core/content_main_delegate_qt.cpp
@@ -59,7 +59,9 @@
#include "base/cpu.h"
#endif
-#include <QLocale>
+#if defined(OS_LINUX)
+#include "ui/base/ui_base_switches.h"
+#endif
namespace QtWebEngineCore {
@@ -135,6 +137,15 @@ content::ContentBrowserClient *ContentMainDelegateQt::CreateContentBrowserClient
content::ContentRendererClient *ContentMainDelegateQt::CreateContentRendererClient()
{
+#if defined(OS_LINUX)
+ base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess();
+
+ if (parsedCommandLine->HasSwitch(switches::kLang)) {
+ const std::string &locale = parsedCommandLine->GetSwitchValueASCII(switches::kLang);
+ ui::ResourceBundle::GetSharedInstance().ReloadLocaleResources(locale);
+ }
+#endif
+
return new ContentRendererClientQt;
}
diff --git a/src/core/core_gyp_generator.pro b/src/core/core_gyp_generator.pro
index cdff4ed64..83de53d0d 100644
--- a/src/core/core_gyp_generator.pro
+++ b/src/core/core_gyp_generator.pro
@@ -141,6 +141,7 @@ HEADERS = \
file_picker_controller.h \
gl_context_qt.h \
gl_surface_qt.h \
+ global_descriptors_qt.h \
javascript_dialog_controller_p.h \
javascript_dialog_controller.h \
javascript_dialog_manager_qt.h \
diff --git a/src/core/global_descriptors_qt.h b/src/core/global_descriptors_qt.h
new file mode 100644
index 000000000..e9d490a2e
--- /dev/null
+++ b/src/core/global_descriptors_qt.h
@@ -0,0 +1,10 @@
+#ifndef GLOBAL_DESCRIPTORS_QT_H
+#define GLOBAL_DESCRIPTORS_QT_H
+
+#include "content/public/common/content_descriptors.h"
+
+enum {
+ kWebEngineLocale = kContentIPCDescriptorMax + 1,
+};
+
+#endif // GLOBAL_DESCRIPTORS_QT_H
diff --git a/src/core/resource_bundle_qt.cpp b/src/core/resource_bundle_qt.cpp
index ba25cc543..115dc56dc 100644
--- a/src/core/resource_bundle_qt.cpp
+++ b/src/core/resource_bundle_qt.cpp
@@ -38,10 +38,20 @@
****************************************************************************/
#include "base/command_line.h"
+#include "base/metrics/histogram.h"
#include "content/public/common/content_switches.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/data_pack.h"
#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/ui_base_switches.h"
+
#include "web_engine_library_info.h"
+#if defined(OS_LINUX)
+#include "base/posix/global_descriptors.h"
+#include "global_descriptors_qt.h"
+#endif
+
namespace ui {
void ResourceBundle::LoadCommonResources()
@@ -60,4 +70,62 @@ gfx::Image& ResourceBundle::GetNativeImageNamed(int resource_id)
return GetEmptyImage();
}
+bool ResourceBundle::LocaleDataPakExists(const std::string& locale)
+{
+#if defined(OS_LINUX)
+ base::CommandLine *parsed_command_line = base::CommandLine::ForCurrentProcess();
+ std::string process_type = parsed_command_line->GetSwitchValueASCII(switches::kProcessType);
+ if (process_type == switches::kRendererProcess) {
+ // The Renderer Process is sandboxed thus only one locale is available in it.
+ // The particular one is passed by the --lang command line option.
+ if (!parsed_command_line->HasSwitch(switches::kLang) || parsed_command_line->GetSwitchValueASCII(switches::kLang) != locale)
+ return false;
+
+ auto global_descriptors = base::GlobalDescriptors::GetInstance();
+ return global_descriptors->MaybeGet(kWebEngineLocale) != -1;
+ }
+#endif
+
+ return !GetLocaleFilePath(locale, true).empty();
+}
+
+std::string ResourceBundle::LoadLocaleResources(const std::string& pref_locale)
+{
+ DCHECK(!locale_resources_data_.get()) << "locale.pak already loaded";
+
+ std::string app_locale = l10n_util::GetApplicationLocale(pref_locale);
+
+#if defined(OS_LINUX)
+ int locale_fd = base::GlobalDescriptors::GetInstance()->MaybeGet(kWebEngineLocale);
+ if (locale_fd > -1) {
+ scoped_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P));
+ data_pack->LoadFromFile(base::File(locale_fd));
+ locale_resources_data_.reset(data_pack.release());
+ return app_locale;
+ }
+#endif
+
+ base::FilePath locale_file_path = GetOverriddenPakPath();
+ if (locale_file_path.empty())
+ locale_file_path = GetLocaleFilePath(app_locale, true);
+
+ if (locale_file_path.empty()) {
+ // It's possible that there is no locale.pak.
+ LOG(WARNING) << "locale_file_path.empty() for locale " << app_locale;
+ return std::string();
+ }
+
+ scoped_ptr<DataPack> data_pack(new DataPack(SCALE_FACTOR_100P));
+ if (!data_pack->LoadFromPath(locale_file_path)) {
+ UMA_HISTOGRAM_ENUMERATION("ResourceBundle.LoadLocaleResourcesError",
+ logging::GetLastSystemErrorCode(), 16000);
+ LOG(ERROR) << "failed to load locale.pak";
+ NOTREACHED();
+ return std::string();
+ }
+
+ locale_resources_data_.reset(data_pack.release());
+ return app_locale;
+}
+
} // namespace ui
diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp
index 2de3d39ff..a81a26d16 100644
--- a/src/core/web_engine_library_info.cpp
+++ b/src/core/web_engine_library_info.cpp
@@ -332,8 +332,16 @@ base::string16 WebEngineLibraryInfo::getApplicationName()
std::string WebEngineLibraryInfo::getApplicationLocale()
{
base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess();
- if (!parsedCommandLine->HasSwitch(switches::kLang))
- return QLocale().bcp47Name().toStdString();
+ if (!parsedCommandLine->HasSwitch(switches::kLang)) {
+ const QString &locale = QLocale().bcp47Name();
+
+ // QLocale::bcp47Name returns "en" for American English locale. Chromium requires the "US" suffix
+ // to clarify the dialect and ignores the shorter version.
+ if (locale == "en")
+ return "en-US";
+
+ return locale.toStdString();
+ }
return parsedCommandLine->GetSwitchValueASCII(switches::kLang);
}
diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
index 1c5461fa7..d59fa92e9 100644
--- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
+++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
@@ -76,6 +76,8 @@ private Q_SLOTS:
void stopSettingFocusWhenDisabled_data();
void inputEventForwardingDisabledWhenActiveFocusOnPressDisabled();
+ void changeLocale();
+
private:
inline QQuickWebEngineView *newWebEngineView();
inline QQuickWebEngineView *webEngineView() const;
@@ -652,5 +654,40 @@ void tst_QQuickWebEngineView::inputEventForwardingDisabledWhenActiveFocusOnPress
QTRY_COMPARE_WITH_TIMEOUT(view->hasActiveFocus(), true, 1000);
}
+void tst_QQuickWebEngineView::changeLocale()
+{
+ QUrl url("http://non.existent/");
+
+ QLocale::setDefault(QLocale("de"));
+ QQuickWebEngineView *viewDE = newWebEngineView();
+ QSignalSpy titleSpyHU(viewDE, SIGNAL(titleChanged()));
+
+ viewDE->setUrl(url);
+ QVERIFY(waitForLoadFailed(viewDE));
+ QTRY_COMPARE(titleSpyHU.size(), 2);
+ QCOMPARE(viewDE->title(), QStringLiteral("Nicht verf\u00FCgbar: %1").arg(url.toString()));
+
+ QLocale::setDefault(QLocale("en"));
+ QQuickWebEngineView *viewEN = newWebEngineView();
+ QSignalSpy titleSpyEN(viewEN, SIGNAL(titleChanged()));
+
+ viewEN->setUrl(url);
+ QVERIFY(waitForLoadFailed(viewEN));
+ QTRY_COMPARE(titleSpyEN.size(), 2);
+ QCOMPARE(viewEN->title(), QStringLiteral("%1 is not available").arg(url.toString()));
+
+ viewDE->setUrl(QUrl("about:blank"));
+ QVERIFY(waitForLoadSucceeded(viewDE));
+ titleSpyHU.clear();
+
+ viewDE->setUrl(url);
+ QVERIFY(waitForLoadFailed(viewDE));
+ QTRY_COMPARE(titleSpyHU.size(), 2);
+ QCOMPARE(viewDE->title(), QStringLiteral("Nicht verf\u00FCgbar: %1").arg(url.toString()));
+
+ delete viewDE;
+ delete viewEN;
+}
+
QTEST_MAIN(tst_QQuickWebEngineView)
#include "tst_qquickwebengineview.moc"
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 52a696d66..e3ca30ef5 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -74,6 +74,8 @@ private Q_SLOTS:
void doNotSendMouseKeyboardEventsWhenDisabled_data();
void stopSettingFocusWhenDisabled();
void stopSettingFocusWhenDisabled_data();
+
+ void changeLocale();
};
// This will be called before the first test function is executed.
@@ -741,5 +743,35 @@ void tst_QWebEngineView::stopSettingFocusWhenDisabled_data()
QTest::newRow("disabled view does not get focus") << false << false;
}
+void tst_QWebEngineView::changeLocale()
+{
+ QUrl url("http://non.existent/");
+
+ QLocale::setDefault(QLocale("de"));
+ QWebEngineView viewDE;
+ viewDE.setUrl(url);
+
+ QVERIFY(waitForSignal(&viewDE, SIGNAL(titleChanged(QString))));
+ QVERIFY(waitForSignal(&viewDE, SIGNAL(loadFinished(bool))));
+ QCOMPARE(viewDE.title(), QStringLiteral("Nicht verf\u00FCgbar: %1").arg(url.toString()));
+
+ QLocale::setDefault(QLocale("en"));
+ QWebEngineView viewEN;
+ viewEN.setUrl(url);
+
+ QVERIFY(waitForSignal(&viewEN, SIGNAL(titleChanged(QString))));
+ QVERIFY(waitForSignal(&viewEN, SIGNAL(loadFinished(bool))));
+ QCOMPARE(viewEN.title(), QStringLiteral("%1 is not available").arg(url.toString()));
+
+ viewDE.setUrl(QUrl("about:blank"));
+ QVERIFY(waitForSignal(&viewDE, SIGNAL(loadFinished(bool))));
+
+ viewDE.setUrl(url);
+
+ QVERIFY(waitForSignal(&viewDE, SIGNAL(titleChanged(QString))));
+ QVERIFY(waitForSignal(&viewDE, SIGNAL(loadFinished(bool))));
+ QCOMPARE(viewDE.title(), QStringLiteral("Nicht verf\u00FCgbar: %1").arg(url.toString()));
+}
+
QTEST_MAIN(tst_QWebEngineView)
#include "tst_qwebengineview.moc"