| /**************************************************************************** |
| ** |
| ** Copyright (C) 2013 BlackBerry Limited. All rights reserved. |
| ** Copyright (C) 2016 The Qt Company Ltd. |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the QtWebEngine module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "web_engine_library_info.h" |
| |
| #include "base/base_paths.h" |
| #include "base/command_line.h" |
| #include "base/files/file_util.h" |
| #include "components/spellcheck/spellcheck_buildflags.h" |
| #include "content/public/common/content_paths.h" |
| #include "ui/base/ui_base_paths.h" |
| #include "ui/base/ui_base_switches.h" |
| #include "type_conversion.h" |
| |
| #include <QByteArray> |
| #include <QCoreApplication> |
| #include <QDir> |
| #include <QFileInfo> |
| #include <QLibraryInfo> |
| #include <QLocale> |
| #include <QStandardPaths> |
| #include <QString> |
| |
| #ifndef QTWEBENGINEPROCESS_NAME |
| #error "No name defined for QtWebEngine's process" |
| #endif |
| |
| using namespace QtWebEngineCore; |
| |
| namespace { |
| |
| QString fallbackDir() { |
| static QString directory = QDir::homePath() % QLatin1String("/.") % QCoreApplication::applicationName(); |
| return directory; |
| } |
| |
| #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) |
| static inline CFBundleRef frameworkBundle() |
| { |
| return CFBundleGetBundleWithIdentifier(CFSTR("org.qt-project.Qt.QtWebEngineCore")); |
| } |
| |
| static QString getPath(CFBundleRef frameworkBundle) |
| { |
| QString path; |
| // The following is a fix for QtWebEngineProcess crashes on OS X 10.7 and before. |
| // We use it for the other OS X versions as well to make sure it works and because |
| // the directory structure should be the same. |
| if (qApp->applicationName() == QLatin1String(QTWEBENGINEPROCESS_NAME)) { |
| path = QDir::cleanPath(qApp->applicationDirPath() % QLatin1String("/../../../..")); |
| } else if (frameworkBundle) { |
| CFURLRef bundleUrl = CFBundleCopyBundleURL(frameworkBundle); |
| CFStringRef bundlePath = CFURLCopyFileSystemPath(bundleUrl, kCFURLPOSIXPathStyle); |
| path = QString::fromCFString(bundlePath); |
| CFRelease(bundlePath); |
| CFRelease(bundleUrl); |
| } |
| return path; |
| } |
| |
| static QString getResourcesPath(CFBundleRef frameworkBundle) |
| { |
| QString path; |
| // The following is a fix for QtWebEngineProcess crashes on OS X 10.7 and before. |
| // We use it for the other OS X versions as well to make sure it works and because |
| // the directory structure should be the same. |
| if (qApp->applicationName() == QLatin1String(QTWEBENGINEPROCESS_NAME)) { |
| path = getPath(frameworkBundle) % QLatin1String("/Resources"); |
| } else if (frameworkBundle) { |
| CFURLRef resourcesRelativeUrl = CFBundleCopyResourcesDirectoryURL(frameworkBundle); |
| CFStringRef resourcesRelativePath = CFURLCopyFileSystemPath(resourcesRelativeUrl, kCFURLPOSIXPathStyle); |
| path = getPath(frameworkBundle) % QLatin1Char('/') % QString::fromCFString(resourcesRelativePath); |
| CFRelease(resourcesRelativePath); |
| CFRelease(resourcesRelativeUrl); |
| } |
| return path; |
| } |
| #endif |
| |
| #if defined(OS_MACOSX) |
| static QString getMainApplicationResourcesPath() |
| { |
| QString resourcesPath; |
| CFBundleRef mainBundle = CFBundleGetMainBundle(); |
| if (!mainBundle) |
| return resourcesPath; |
| |
| // Will point to Resources inside an app bundle, or in case if the application is not packaged |
| // as a bundle, will point to the application directory, where the resources are assumed to be |
| // found. |
| CFURLRef resourcesRelativeUrl = CFBundleCopyResourcesDirectoryURL(mainBundle); |
| if (!resourcesRelativeUrl) |
| return resourcesPath; |
| |
| CFURLRef resourcesAbsoluteUrl = CFURLCopyAbsoluteURL(resourcesRelativeUrl); |
| CFStringRef resourcesAbolutePath = CFURLCopyFileSystemPath(resourcesAbsoluteUrl, |
| kCFURLPOSIXPathStyle); |
| resourcesPath = QString::fromCFString(resourcesAbolutePath); |
| CFRelease(resourcesAbolutePath); |
| CFRelease(resourcesAbsoluteUrl); |
| CFRelease(resourcesRelativeUrl); |
| |
| return resourcesPath; |
| } |
| |
| #endif |
| |
| QString subProcessPath() |
| { |
| static QString processPath; |
| if (processPath.isEmpty()) { |
| #if defined(OS_WIN) |
| const QString processBinary = QLatin1String(QTWEBENGINEPROCESS_NAME) % QLatin1String(".exe"); |
| #else |
| const QString processBinary = QLatin1String(QTWEBENGINEPROCESS_NAME); |
| #endif |
| |
| QStringList candidatePaths; |
| const QString fromEnv = qEnvironmentVariable("QTWEBENGINEPROCESS_PATH"); |
| if (!fromEnv.isEmpty()) { |
| // Only search in QTWEBENGINEPROCESS_PATH if set |
| candidatePaths << fromEnv; |
| } else { |
| #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) |
| candidatePaths << getPath(frameworkBundle()) |
| % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME); |
| #else |
| candidatePaths << QLibraryInfo::location(QLibraryInfo::LibraryExecutablesPath) |
| % QLatin1Char('/') % processBinary; |
| #endif |
| candidatePaths << QCoreApplication::applicationDirPath() |
| % QLatin1Char('/') % processBinary; |
| } |
| |
| for (const QString &candidate : qAsConst(candidatePaths)) { |
| if (QFileInfo::exists(candidate)) { |
| processPath = candidate; |
| break; |
| } |
| } |
| if (processPath.isEmpty()) |
| qFatal("Could not find %s", processBinary.toUtf8().constData()); |
| |
| } |
| |
| |
| return processPath; |
| } |
| |
| QString localesPath() |
| { |
| static bool initialized = false; |
| static QString potentialLocalesPath = |
| #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) |
| getResourcesPath(frameworkBundle()) % QLatin1String("/qtwebengine_locales"); |
| #else |
| QLibraryInfo::location(QLibraryInfo::TranslationsPath) % QDir::separator() % QLatin1String("qtwebengine_locales"); |
| #endif |
| |
| if (!initialized) { |
| initialized = true; |
| if (!QFileInfo::exists(potentialLocalesPath)) { |
| qWarning("Installed Qt WebEngine locales directory not found at location %s. Trying application directory...", qPrintable(potentialLocalesPath)); |
| potentialLocalesPath = QCoreApplication::applicationDirPath() % QDir::separator() % QLatin1String("qtwebengine_locales"); |
| } |
| if (!QFileInfo::exists(potentialLocalesPath)) { |
| qWarning("Qt WebEngine locales directory not found at location %s. Trying fallback directory... Translations MAY NOT not be correct.", qPrintable(potentialLocalesPath)); |
| potentialLocalesPath = fallbackDir(); |
| } |
| } |
| |
| return potentialLocalesPath; |
| } |
| |
| #if QT_CONFIG(webengine_spellchecker) |
| QString dictionariesPath() |
| { |
| static QString potentialDictionariesPath; |
| static bool initialized = false; |
| QStringList candidatePaths; |
| if (!initialized) { |
| initialized = true; |
| |
| const QString fromEnv = qEnvironmentVariable("QTWEBENGINE_DICTIONARIES_PATH"); |
| if (!fromEnv.isEmpty()) { |
| // Only search in QTWEBENGINE_DICTIONARIES_PATH if set |
| candidatePaths << fromEnv; |
| } else { |
| // First try to find dictionaries near the application. |
| #ifdef OS_MACOSX |
| QString resourcesDictionariesPath = getMainApplicationResourcesPath() |
| % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); |
| candidatePaths << resourcesDictionariesPath; |
| #endif |
| QString applicationDictionariesPath = QCoreApplication::applicationDirPath() |
| % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); |
| candidatePaths << applicationDictionariesPath; |
| |
| // Then try to find dictionaries near the installed library. |
| #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) |
| QString frameworkDictionariesPath = getResourcesPath(frameworkBundle()) |
| % QLatin1String("/qtwebengine_dictionaries"); |
| candidatePaths << frameworkDictionariesPath; |
| #endif |
| |
| QString libraryDictionariesPath = QLibraryInfo::location(QLibraryInfo::DataPath) |
| % QDir::separator() % QLatin1String("qtwebengine_dictionaries"); |
| candidatePaths << libraryDictionariesPath; |
| } |
| |
| for (const QString &candidate : qAsConst(candidatePaths)) { |
| if (QFileInfo::exists(candidate)) { |
| potentialDictionariesPath = candidate; |
| break; |
| } |
| } |
| } |
| |
| return potentialDictionariesPath; |
| } |
| #endif // QT_CONFIG(webengine_spellchecker) |
| |
| QString resourcesDataPath() |
| { |
| static bool initialized = false; |
| static QString potentialResourcesPath = |
| #if defined(OS_MACOSX) && defined(QT_MAC_FRAMEWORK_BUILD) |
| getResourcesPath(frameworkBundle()); |
| #else |
| QLibraryInfo::location(QLibraryInfo::DataPath) % QLatin1String("/resources"); |
| #endif |
| if (!initialized) { |
| initialized = true; |
| if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { |
| qWarning("Qt WebEngine resources not found at %s. Trying parent directory...", qPrintable(potentialResourcesPath)); |
| potentialResourcesPath = QLibraryInfo::location(QLibraryInfo::DataPath); |
| } |
| if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { |
| qWarning("Qt WebEngine resources not found at %s. Trying application directory...", qPrintable(potentialResourcesPath)); |
| potentialResourcesPath = QCoreApplication::applicationDirPath(); |
| } |
| if (!QFileInfo::exists(potentialResourcesPath % QLatin1String("/qtwebengine_resources.pak"))) { |
| qWarning("Qt WebEngine resources not found at %s. Trying fallback directory... The application MAY NOT work.", qPrintable(potentialResourcesPath)); |
| potentialResourcesPath = fallbackDir(); |
| } |
| } |
| |
| return potentialResourcesPath; |
| } |
| } // namespace |
| |
| base::FilePath WebEngineLibraryInfo::getPath(int key) |
| { |
| QString directory; |
| switch (key) { |
| case QT_RESOURCES_PAK: |
| return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_resources.pak")); |
| case QT_RESOURCES_100P_PAK: |
| return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_resources_100p.pak")); |
| case QT_RESOURCES_200P_PAK: |
| return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_resources_200p.pak")); |
| case QT_RESOURCES_DEVTOOLS_PAK: |
| return toFilePath(resourcesDataPath() % QLatin1String("/qtwebengine_devtools_resources.pak")); |
| case base::FILE_EXE: |
| case content::CHILD_PROCESS_EXE: |
| return toFilePath(subProcessPath()); |
| #if defined(OS_POSIX) |
| case base::DIR_CACHE: |
| directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); |
| break; |
| case base::DIR_HOME: |
| directory = QDir::homePath(); |
| break; |
| #endif |
| case base::DIR_USER_DESKTOP: |
| directory = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); |
| break; |
| case base::DIR_QT_LIBRARY_DATA: |
| return toFilePath(resourcesDataPath()); |
| case ui::DIR_LOCALES: |
| return toFilePath(localesPath()); |
| #if QT_CONFIG(webengine_spellchecker) |
| case base::DIR_APP_DICTIONARIES: |
| return toFilePath(dictionariesPath()); |
| #endif |
| default: |
| // Note: the path system expects this function to override the default |
| // behavior. So no need to log an error if we don't support a given |
| // path. The system will just use the default. |
| return base::FilePath(); |
| } |
| |
| return toFilePath(directory.isEmpty() ? fallbackDir() : directory); |
| } |
| |
| base::string16 WebEngineLibraryInfo::getApplicationName() |
| { |
| return toString16(qApp->applicationName()); |
| } |
| |
| std::string WebEngineLibraryInfo::getApplicationLocale() |
| { |
| base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess(); |
| 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); |
| } |