diff options
author | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-02-01 20:50:41 +0100 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@qt.io> | 2017-02-01 20:58:12 +0100 |
commit | b5d7ec9226eee41d9c3516bf51dc48c283e8b13e (patch) | |
tree | 994d2f09fd2106efed07e007becffed6e56a584c | |
parent | 3c4c080e46a8fa229d7e1fdaee82f750b3558aa0 (diff) | |
parent | 2313a580c0e3f0636a12697ba4b872bfdccbcf7f (diff) |
Merge dev into 5.9
Change-Id: Id919bfd67d9d435fd5a05a892151a12ae5bcd3c0
54 files changed, 1517 insertions, 573 deletions
diff --git a/configure.json b/configure.json index 03b9611c1..c91c2e6bf 100644 --- a/configure.json +++ b/configure.json @@ -9,11 +9,13 @@ "commandline": { "options": { "alsa": "boolean", + "embedded": "boolean", "pepper-plugins": "boolean", "printing-and-pdf": "boolean", "proprietary-codecs": "boolean", "pulseaudio": "boolean", - "spellchecker": "boolean" + "spellchecker": "boolean", + "webrtc": "boolean" } }, @@ -41,10 +43,21 @@ "gn": { "label": "system gn", "type": "detectGn" + }, + "embedded": { + "label": "embedded", + "type": "embedded" } }, "features": { + "embedded": { + "label": "Embedded build", + "condition": "config.unix", + "autoDetect": "tests.embedded", + "purpose": "Enables the embedded build configuration", + "output": [ "privateFeature" ] + }, "alsa": { "label": "ALSA", "condition": "config.unix && libs.alsa", @@ -58,14 +71,14 @@ }, "pepper-plugins": { "label": "Pepper Plugins", - "autoDetect": "!features.cross_compile", + "autoDetect": "!features.embedded", "purpose": "Enables use of Pepper Flash and Widevine plugins", "output": [ "privateFeature" ] }, "printing-and-pdf": { "label": "Printing and PDF", "condition": "module.printsupport && features.printer", - "autoDetect": "!features.cross_compile", + "autoDetect": "!features.embedded", "purpose": "Enables printing and output to PDF", "output": [ "privateFeature" ] }, @@ -80,6 +93,12 @@ "purpose": "Enables the use of Chromium's spellchecker", "output": [ "privateFeature" ] }, + "webrtc": { + "label": "WebRTC", + "autoDetect": "!features.embedded", + "purpose": "Enables WebRTC support", + "output": [ "privateFeature" ] + }, "system-ninja": { "label": "Using system ninja", "condition": "tests.ninja", @@ -87,6 +106,7 @@ }, "system-gn": { "label": "Using system gn", + "autoDetect": false, "condition": "tests.gn", "output": [ "privateFeature" ] } @@ -96,11 +116,12 @@ { "section": "Qt WebEngine", "entries": [ + "embedded", "pepper-plugins", "printing-and-pdf", "proprietary-codecs", "spellchecker", - "system-gn", + "webrtc", "system-ninja", { "type": "feature", diff --git a/configure.pri b/configure.pri index b6693aecf..23f31686e 100644 --- a/configure.pri +++ b/configure.pri @@ -23,3 +23,12 @@ defineTest(qtConfTest_detectGn) { qtLog("Building own gn") return(false) } + +defineTest(qtConfTest_embedded) { + lessThan(QT_MINOR_VERSION, 9) { + cross_compile: return(true) + return(false) + } + $$qtConfEvaluate("features.cross_compile"): return(true) + return(false) +} diff --git a/examples/webenginewidgets/spellchecker/webview.cpp b/examples/webenginewidgets/spellchecker/webview.cpp index 86e21ab13..0e52e7628 100644 --- a/examples/webenginewidgets/spellchecker/webview.cpp +++ b/examples/webenginewidgets/spellchecker/webview.cpp @@ -65,7 +65,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) } QWebEngineProfile *profile = page()->profile(); - const QString &language = profile->spellCheckLanguages().first(); + const QStringList &languages = profile->spellCheckLanguages(); QMenu *menu = page()->createStandardContextMenu(); menu->addSeparator(); @@ -83,7 +83,7 @@ void WebView::contextMenuEvent(QContextMenuEvent *event) QAction *action = subMenu->addAction(str); action->setCheckable(true); QString lang = m_spellCheckLanguages[str]; - action->setChecked(language == lang); + action->setChecked(languages.contains(lang)); connect(action, &QAction::triggered, this, [profile, lang](){ profile->setSpellCheckLanguages(QStringList()<<lang); }); diff --git a/src/core/config/common.pri b/src/core/config/common.pri index f822ab7cc..7307c4a46 100644 --- a/src/core/config/common.pri +++ b/src/core/config/common.pri @@ -1,33 +1,79 @@ # Shared configuration for all our supported platforms -# Trigger Qt-specific build conditions. -GYP_CONFIG += use_qt=1 -# We do not want to ship more external binary blobs, so let v8 embed its startup data. -GYP_CONFIG += v8_use_external_startup_data=0 -# WebSpeech requires Google API keys and adds dependencies on speex and flac. -GYP_CONFIG += enable_web_speech=0 -# We do not use or even include the extensions -GYP_CONFIG += enable_extensions=0 - -sanitize_address: GYP_CONFIG += asan=1 -sanitize_thread: GYP_CONFIG += tsan=1 -sanitize_memory: GYP_CONFIG += msan=1 -sanitize_undefined: GYP_CONFIG += ubsan=1 - -use?(printing) { - GYP_CONFIG += enable_basic_printing=1 enable_print_preview=1 -} else { - GYP_CONFIG += enable_basic_printing=0 enable_print_preview=0 -} +use?(gn) { + gn_args += \ + use_qt=true \ + is_component_build=false \ + enable_remoting=false \ + enable_nacl=false \ + use_experimental_allocator_shim=false \ + use_allocator=\"none\" \ + v8_use_external_startup_data=false \ + treat_warnings_as_errors=false -use?(pdf) { - GYP_CONFIG += enable_pdf=1 -} else { - GYP_CONFIG += enable_pdf=0 -} + use?(printing) { + gn_args += enable_basic_printing=true enable_print_preview=true + } else { + gn_args += enable_basic_printing=false enable_print_preview=false + } + + use?(pdf) { + gn_args += enable_pdf=true + } else { + gn_args += enable_pdf=false + } + + use?(pepper_plugins) { + gn_args += enable_plugins=true enable_widevine=true + } else { + gn_args += enable_plugins=false enable_widevine=false + } + + use?(spellchecker) { + gn_args += enable_spellcheck=true + } else { + gn_args += enable_spellcheck=false + } + + use?(webrtc) { + gn_args += enable_webrtc=true + } else { + gn_args += enable_webrtc=false + } -use?(pepper_plugins) { - GYP_CONFIG += enable_plugins=1 enable_widevine=1 } else { - GYP_CONFIG += enable_plugins=0 enable_widevine=0 + # Trigger Qt-specific build conditions. + GYP_CONFIG += use_qt=1 + # We do not want to ship more external binary blobs, so let v8 embed its startup data. + GYP_CONFIG += v8_use_external_startup_data=0 + # WebSpeech requires Google API keys and adds dependencies on speex and flac. + GYP_CONFIG += enable_web_speech=0 + # We do not use or even include the extensions + GYP_CONFIG += enable_extensions=0 + + sanitize_address: GYP_CONFIG += asan=1 + sanitize_thread: GYP_CONFIG += tsan=1 + sanitize_memory: GYP_CONFIG += msan=1 + sanitize_undefined: GYP_CONFIG += ubsan=1 + + use?(printing) { + GYP_CONFIG += enable_basic_printing=1 enable_print_preview=1 + } else { + GYP_CONFIG += enable_basic_printing=0 enable_print_preview=0 + } + + use?(pdf) { + GYP_CONFIG += enable_pdf=1 + } else { + GYP_CONFIG += enable_pdf=0 + } + + use?(pepper_plugins) { + GYP_CONFIG += enable_plugins=1 enable_widevine=1 + } else { + GYP_CONFIG += enable_plugins=0 enable_widevine=0 + } } + +use?(webrtc): GYP_CONFIG += enable_webrtc=1 +else: GYP_CONFIG += enable_webrtc=0 diff --git a/src/core/config/desktop_linux.pri b/src/core/config/desktop_linux.pri index 92491fc1c..e8db4248f 100644 --- a/src/core/config/desktop_linux.pri +++ b/src/core/config/desktop_linux.pri @@ -1,17 +1,29 @@ -GYP_ARGS += "-D qt_os=\"desktop_linux\"" - include(linux.pri) -GYP_CONFIG += \ - desktop_linux=1 +use?(gn) { + gn_args += \ + is_clang=false \ + use_sysroot=false + + use?(icecc) { + gn_args += use_debug_fission=false + } -clang { - GYP_CONFIG += werror= - clang_full_path = $$which($${QMAKE_CXX}) - # Remove the "/bin/clang++" part. - clang_prefix = $$section(clang_full_path, /, 0, -3) - GYP_CONFIG += clang=1 host_clang=1 clang_use_chrome_plugins=0 make_clang_dir=$${clang_prefix} - linux-clang-libc++: GYP_CONFIG += use_system_libcxx=1 } else { - GYP_CONFIG += clang=0 host_clang=0 + + GYP_ARGS += "-D qt_os=\"desktop_linux\"" + + GYP_CONFIG += \ + desktop_linux=1 + + clang { + GYP_CONFIG += werror= + clang_full_path = $$which($${QMAKE_CXX}) + # Remove the "/bin/clang++" part. + clang_prefix = $$section(clang_full_path, /, 0, -3) + GYP_CONFIG += clang=1 host_clang=1 clang_use_chrome_plugins=0 make_clang_dir=$${clang_prefix} + linux-clang-libc++: GYP_CONFIG += use_system_libcxx=1 + } else { + GYP_CONFIG += clang=0 host_clang=0 + } } diff --git a/src/core/config/embedded_linux.pri b/src/core/config/embedded_linux.pri index 08c8c1661..c9de47562 100644 --- a/src/core/config/embedded_linux.pri +++ b/src/core/config/embedded_linux.pri @@ -18,7 +18,6 @@ GYP_CONFIG += \ enable_session_service=0 \ enable_task_manager=0 \ enable_themes=0 \ - enable_webrtc=0 \ gtest_target_type=none \ host_clang=0 \ notifications=0 \ diff --git a/src/core/config/linux.pri b/src/core/config/linux.pri index b91e795ca..8509c0c8e 100644 --- a/src/core/config/linux.pri +++ b/src/core/config/linux.pri @@ -2,6 +2,44 @@ include(common.pri) include($$QTWEBENGINE_OUT_ROOT/qtwebengine-config.pri) QT_FOR_CONFIG += gui-private webengine-private +use?(gn) { + gn_args += \ + use_gconf=false \ + use_gio=false \ + use_kerberos=false \ + linux_use_bundled_binutils=false + + #qtConfig(system-zlib): use?(system_minizip): gn_args += use_system_zlib=true use_system_minizip=true + #qtConfig(system-png): gn_args += use_system_libpng=true + qtConfig(system-jpeg): gn_args += use_system_libjpeg=true + qtConfig(system-harfbuzz): use?(system_harfbuzz): gn_args += use_system_harfbuzz=true + !qtConfig(glib): gn_args += use_glib=false + qtConfig(pulseaudio) { + gn_args += use_pulseaudio=true + } else { + gn_args += use_pulseaudio=false + } + qtConfig(alsa) { + gn_args += use_alsa=true + } else { + gn_args += use_alsa=false + } + + #use?(system_libevent): gn_args += use_system_libevent=true + #use?(system_libwebp): gn_args += use_system_libwebp=true + #use?(system_libsrtp): gn_args += use_system_libsrtp=true + #use?(system_libxslt): gn_args += use_system_libxml=true use_system_libxslt=true + #use?(system_jsoncpp): gn_args += use_system_jsoncpp=true + #use?(system_opus): gn_args += use_system_opus=true + #use?(system_snappy): gn_args += use_system_snappy=true + #use?(system_vpx): gn_args += use_system_libvpx=true + #use?(system_icu): gn_args += use_system_icu=true icu_use_data_file_flag=false + #use?(system_ffmpeg): gn_args += use_system_ffmpeg=true + #use?(system_protobuf): gn_args += use_system_protobuf=true + + #gcc:!clang: greaterThan(QT_GCC_MAJOR_VERSION, 5): gn_args += no_delete_null_pointer_checks=true +} + # linux_use_bundled_gold currently relies on a hardcoded relative path from chromium/src/out/(Release|Debug) # Disable it along with the -Wl,--threads flag just in case gold isn't installed on the system. GYP_CONFIG += \ diff --git a/src/core/config/mac_osx.pri b/src/core/config/mac_osx.pri index dfc8d840b..e52051b0c 100644 --- a/src/core/config/mac_osx.pri +++ b/src/core/config/mac_osx.pri @@ -19,21 +19,42 @@ QMAKE_CLANG_PATH = $$eval(QMAKE_MAC_SDK.macx-clang.$${QMAKE_MAC_SDK}.QMAKE_CXX) QMAKE_CLANG_PATH = "$${QMAKE_CLANG_DIR}/bin/clang++" message("Using clang++ from $${QMAKE_CLANG_PATH}") system("$${QMAKE_CLANG_PATH} --version") -GYP_CONFIG += \ - qt_os=\"mac\" \ - mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" \ - mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ - make_clang_dir=\"$${QMAKE_CLANG_DIR}\" \ - clang_use_chrome_plugins=0 - -# Force touch API is used in 49-based Chromium, which is included starting with 10.10.3 SDK, so we -# disable the API usage if the SDK version is lower. -!isMinOSXSDKVersion(10, 10, 3): GYP_CONFIG += disable_force_touch=1 - -# Pass a supported -fstack-protect flag depending on Xcode version. -lessThan(QMAKE_XCODE_VERSION, 6.3) { - GYP_CONFIG += use_xcode_stack_protector_strong=0 -} -QMAKE_MAC_SDK_PATH = "$$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path)" -exists($$QMAKE_MAC_SDK_PATH): GYP_CONFIG += mac_sdk_path=\"$${QMAKE_MAC_SDK_PATH}\" + +use?(gn) { + gn_args += \ + is_clang=true \ + use_sysroot=false \ + use_kerberos=false \ + clang_base_path=\"$${QMAKE_CLANG_DIR}\" \ + clang_use_chrome_plugins=false \ + mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ + mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" + + use?(spellchecker) { + use?(native_spellchecker): gn_args += use_browser_spellchecker=true + else: gn_args += use_browser_spellchecker=false + } else { + macos: gn_args += use_browser_spellchecker=false + } + +} else { + GYP_CONFIG += \ + qt_os=\"mac\" \ + mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" \ + mac_deployment_target=\"$${QMAKE_MACOSX_DEPLOYMENT_TARGET}\" \ + make_clang_dir=\"$${QMAKE_CLANG_DIR}\" \ + clang_use_chrome_plugins=0 + + # Force touch API is used in 49-based Chromium, which is included starting with 10.10.3 SDK, so we + # disable the API usage if the SDK version is lower. + !isMinOSXSDKVersion(10, 10, 3): GYP_CONFIG += disable_force_touch=1 + + # Pass a supported -fstack-protect flag depending on Xcode version. + lessThan(QMAKE_XCODE_VERSION, 6.3) { + GYP_CONFIG += use_xcode_stack_protector_strong=0 + } + + QMAKE_MAC_SDK_PATH = "$$eval(QMAKE_MAC_SDK.$${QMAKE_MAC_SDK}.path)" + exists($$QMAKE_MAC_SDK_PATH): GYP_CONFIG += mac_sdk_path=\"$${QMAKE_MAC_SDK_PATH}\" +} diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 787586540..f9b6f31d8 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -386,7 +386,7 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* // SpellCheckMessageFilter is required for both Hunspell and Native configurations. host->AddFilter(new SpellCheckMessageFilter(id)); #endif -#if defined(Q_OS_MACOS) && defined(USE_BROWSER_SPELLCHECKER) +#if defined(Q_OS_MACOS) && defined(ENABLE_SPELLCHECK) && defined(USE_BROWSER_SPELLCHECKER) host->AddFilter(new SpellCheckMessageFilterPlatform(id)); #endif #if defined(ENABLE_BASIC_PRINTING) diff --git a/src/core/core.pro b/src/core/core.pro index cda885921..a2f3c3753 100644 --- a/src/core/core.pro +++ b/src/core/core.pro @@ -14,15 +14,38 @@ core_module.depends = core_api core_generator.file = core_generator.pro core_generator.depends = core_headers - use?(gn) { + # core_gn_generator.pro is a dummy .pro file that is used by qmake + # to generate our main BUILD.gn file + + core_icu.files = $$OUT_PWD/$$getConfigDir()/icudtl.dat + core_icu.path = $$[QT_INSTALL_DATA]/resources + core_icu.CONFIG += no_check_exist + + core_locales.files = $$OUT_PWD/$$getConfigDir()/qtwebengine_locales/*.pak + core_locales.path = $$[QT_INSTALL_TRANSLATIONS]/qtwebengine_locales + core_locales.CONFIG += no_check_exist + + core_resources.files = \ + $$OUT_PWD/$$getConfigDir()/qtwebengine_resources.pak \ + $$OUT_PWD/$$getConfigDir()/qtwebengine_resources_100p.pak \ + $$OUT_PWD/$$getConfigDir()/qtwebengine_resources_200p.pak \ + $$OUT_PWD/$$getConfigDir()/qtwebengine_devtools_resources.pak + core_resources.path = $$[QT_INSTALL_DATA]/resources + core_resources.CONFIG += no_check_exist + INSTALLS += core_resources core_locales core_icu gn_run.file = gn_run.pro gn_run.depends = core_generator - SUBDIRS += core_headers \ + core_api.depends = gn_run + + SUBDIRS += \ + core_headers \ core_generator \ - gn_run + gn_run \ + core_api \ + core_module } else { # gyp_run.pro calls gyp through gyp_qtwebengine on the qmake step, and ninja on the make step. diff --git a/src/core/core_generator.pro b/src/core/core_generator.pro index e1e7ab1d9..ed47a47e9 100644 --- a/src/core/core_generator.pro +++ b/src/core/core_generator.pro @@ -12,7 +12,15 @@ include(core_common.pri) macos { # This fixes namespace builds on macOS. Specifically namespace ambiguity issues between Qt and # Chromium forward declarations of NSString. - forward_declaration_macro = $$shell_quote(\"Q_FORWARD_DECLARE_OBJC_CLASS(name)=class name;\") + contains(WEBENGINE_CONFIG, use_gn) { + # The single quotes are present so that qmake iteration does not interpret the space as + # delimiting a new value, they are removed before writing to the GN file, and the final shell + # quoting is done by GN itself. + forward_declaration_macro = "'Q_FORWARD_DECLARE_OBJC_CLASS(name)=class name;'" + } else { + # For GYP, quoting should be done by qmake itself. + forward_declaration_macro = $$shell_quote(\"Q_FORWARD_DECLARE_OBJC_CLASS(name)=class name;\") + } } else { forward_declaration_macro = "Q_FORWARD_DECLARE_OBJC_CLASS=QT_FORWARD_DECLARE_CLASS" } diff --git a/src/core/core_gn_config.pri b/src/core/core_gn_config.pri index ea45977f5..fb671ddb2 100644 --- a/src/core/core_gn_config.pri +++ b/src/core/core_gn_config.pri @@ -1,6 +1,10 @@ CONFIG = gn_generator $$CONFIG GN_SRC_DIR = $$PWD -GN_FILE = $$OUT_PWD/BUILD.gn +GN_FILE = $$OUT_PWD/$$getConfigDir()/BUILD.gn GN_FIND_MOCABLES_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_find_mocables.py) GN_RUN_BINARY_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_run_binary.py) +GN_IMPORTS = $$PWD/qtwebengine.gni +GN_INCLUDES = $$PWD/qtwebengine_sources.gni $$PWD/qtwebengine_resources.gni +GN_CREATE_PRI = true +QMAKE_INTERNAL_INCLUDED_FILES = $$GN_IMPORTS $$GN_INCLUDES $$GN_FILE diff --git a/src/core/core_module.pro b/src/core/core_module.pro index 596993457..a7853e524 100644 --- a/src/core/core_module.pro +++ b/src/core/core_module.pro @@ -4,9 +4,11 @@ include(core_common.pri) # Needed to set a CFBundleIdentifier QMAKE_INFO_PLIST = Info_mac.plist -# Look for linking information produced by gyp for our target according to core_generated.gyp -!include($$OUT_PWD/$$getConfigDir()/$${TARGET}_linking.pri) { - error("Could not find the linking information that gyp should have generated.") +use?(gn): linking_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}.pri +else: linking_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}_linking.pri + +!include($$linking_pri) { + error("Could not find the linking information that gyp/gn should have generated.") } load(qt_module) @@ -17,6 +19,30 @@ api_library_path = $$OUT_PWD/api/$$getConfigDir() # Do not precompile any headers. We are only interested in the linker step. PRECOMPILED_HEADER = +use?(gn){ + isEmpty(NINJA_OBJECTS): error("Missing object files from QtWebEngineCore linking pri.") + isEmpty(NINJA_LFLAGS): error("Missing linker flags from QtWebEngineCore linking pri") + isEmpty(NINJA_ARCHIVES): error("Missing archive files from QtWebEngineCore linking pri") + isEmpty(NINJA_LIBS): error("Missing library files from QtWebEngineCore linking pri") + NINJA_OBJECTS = $$eval($$list($$NINJA_OBJECTS)) + # Do manual response file linking for macOS and Linux + unix { + RSP_FILE = $$OUT_PWD/$$getConfigDir()/$${TARGET}.rsp + for(object, NINJA_OBJECTS): RSP_CONTENT += $$object + write_file($$RSP_FILE, RSP_CONTENT) + macos:LIBS_PRIVATE += -Wl,-filelist,$$shell_quote($$RSP_FILE) + linux:LIBS_PRIVATE += @$$RSP_FILE + } else { + OBJECTS = $$NINJA_OBJECTS + } + linux: LIBS_PRIVATE += -Wl,--start-group $$NINJA_ARCHIVES -Wl,--end-group + else: LIBS_PRIVATE += $$NINJA_ARCHIVES + LIBS_PRIVATE += $$NINJA_LIB_DIRS $$NINJA_LIBS + QMAKE_LFLAGS += $$NINJA_LFLAGS + POST_TARGETDEPS += $$NINJA_TARGETDEPS +} + + LIBS_PRIVATE += -L$$api_library_path CONFIG *= no_smart_library_merge osx { @@ -44,7 +70,12 @@ qtConfig(egl): CONFIG += egl linux:qtConfig(separate_debug_info): QMAKE_POST_LINK="cd $(DESTDIR) && $(STRIP) --strip-unneeded $(TARGET)" -REPACK_DIR = $$OUT_PWD/$$getConfigDir()/gen/repack +use?(gn) { + REPACK_DIR = $$OUT_PWD/$$getConfigDir() +} else { + REPACK_DIR = $$OUT_PWD/$$getConfigDir()/gen/repack +} + # Duplicated from resources/resources.gyp LOCALE_LIST = am ar bg bn ca cs da de el en-GB en-US es-419 es et fa fi fil fr gu he hi hr hu id it ja kn ko lt lv ml mr ms nb nl pl pt-BR pt-PT ro ru sk sl sr sv sw ta te th tr uk vi zh-CN zh-TW for(LOC, LOCALE_LIST) { diff --git a/src/core/gn_run.pro b/src/core/gn_run.pro index c379f9510..534f0c7b3 100644 --- a/src/core/gn_run.pro +++ b/src/core/gn_run.pro @@ -7,8 +7,15 @@ TEMPLATE = aux build_pass|!debug_and_release { + macos: include(config/mac_osx.pri) + linux: include(config/desktop_linux.pri) + isEmpty(gn_args): error(No gn_args found please make sure you have valid configuration.) + ninja_binary = ninja + gn_binary = gn + runninja.target = run_ninja + rungn.target = run_gn !qtConfig(system-ninja) { ninja_binary = $$shell_quote($$shell_path($$ninjaPath())) @@ -18,18 +25,35 @@ build_pass|!debug_and_release { runninja.depends = buildninja } + CONFIG(release, debug|release): + gn_args += is_debug=false + + gn_args += "qtwebengine_target=\"$$shell_path($$OUT_PWD/$$getConfigDir()):QtWebEngineCore\"" + !qtConfig(system-gn) { + gn_binary = $$shell_quote($$shell_path($$gnPath())) buildgn.target = build_gn - buildgn.commands = $$buildGn() - !qtConfig(system-ninja): buildgn.depends = buildninja + buildgn.commands = $$buildGn($$gn_args) + !qtConfig(system-ninja) { + buildgn.depends = buildninja + rungn.depends = buildninja + } QMAKE_EXTRA_TARGETS += buildgn - runninja.depends = buildgn } - runninja.commands = $$ninja_binary \$\(NINJAFLAGS\) -C $$shell_quote($$OUT_PWD/$$getConfigDir()) + gn_args = $$shell_quote($$gn_args) + gn_src_root = $$shell_quote($$shell_path($$QTWEBENGINE_ROOT/$$getChromiumSrcDir())) + gn_build_root = $$shell_quote($$shell_path($$OUT_PWD/$$getConfigDir())) + rungn.commands = $$gn_binary gen $$gn_build_root --args=$$gn_args --root=$$gn_src_root + QMAKE_EXTRA_TARGETS += rungn + + runninja.commands = $$ninja_binary \$\(NINJAFLAGS\) -v -C $$shell_quote($$OUT_PWD/$$getConfigDir()) QtWebEngineCore + runninja.depends += rungn QMAKE_EXTRA_TARGETS += runninja - default_target.depends = buildgn + build_pass:build_all: default_target.target = all + else: default_target.target = first + default_target.depends = runninja QMAKE_EXTRA_TARGETS += default_target } else { diff --git a/src/core/gyp_run.pro b/src/core/gyp_run.pro index c583845e9..fa8f73de4 100644 --- a/src/core/gyp_run.pro +++ b/src/core/gyp_run.pro @@ -9,7 +9,7 @@ isQtMinimum(5, 8) { TEMPLATE = aux -cross_compile { +contains(WEBENGINE_CONFIG, embedded_build) { GYP_ARGS = "-D qt_cross_compile=1" posix: GYP_ARGS += "-D os_posix=1" qnx: include(config/embedded_qnx.pri) diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni new file mode 100644 index 000000000..4e561e7a9 --- /dev/null +++ b/src/core/qtwebengine.gni @@ -0,0 +1,47 @@ +chromium_version = exec_script("//build/util/version.py", [ "-f", rebase_path("//chrome/VERSION"), + "-t", "@MAJOR@.@MINOR@.@BUILD@.@PATCH@"], + "list lines") + +declare_args() { + use_qt = true +} + +include_dirs = [ + "//skia/config", + "//third_party/skia/include/core" +] + +deps = [ + "//base", + "//components/cdm/renderer", + "//components/devtools_http_handler", + "//components/error_page/common", + "//components/keyed_service/content", + "//components/visitedlink/browser", + "//components/visitedlink/renderer", + "//components/web_cache/browser", + "//components/web_cache/public/interfaces", + "//components/web_cache/renderer", + "//content/public/app:browser", + "//content/public/browser", + "//content/public/common", + "//net:net_browser_services", + "//services/shell/public/cpp", + "//skia", + "//third_party/WebKit/public:blink", + "//third_party/widevine/cdm:version_h", + "//ui/accessibility", + "//third_party/mesa:mesa_headers", + ":qtwebengine_sources", + ":qtwebengine_resources" +] + +if (enable_widevine) { + deps += [ "//components/cdm/renderer"] +} + +# fixme: +defines = [ + "QTWEBENGINEPROCESS_NAME=\"QtWebEngineProcess\"", + "CHROMIUM_VERSION=\"" + chromium_version[0] + "\"" +] diff --git a/src/core/qtwebengine.gypi b/src/core/qtwebengine.gypi index 5131ce8cc..b83b1cbfa 100644 --- a/src/core/qtwebengine.gypi +++ b/src/core/qtwebengine.gypi @@ -5,6 +5,11 @@ 'variables': { 'version_script_location%': '<(chromium_src_dir)/build/util/version.py', }, + 'configurations': { + 'Release': { + 'defines': [ 'QT_NO_DEBUG' ], + }, + }, 'dependencies': [ '<(chromium_src_dir)/base/base.gyp:base', '<(chromium_src_dir)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', diff --git a/src/core/qtwebengine_resources.gni b/src/core/qtwebengine_resources.gni new file mode 100644 index 000000000..e3cd42169 --- /dev/null +++ b/src/core/qtwebengine_resources.gni @@ -0,0 +1,86 @@ +import("//tools/grit/repack.gni") +import("//build/config/locales.gni") +import("//chrome/chrome_repack_locales.gni") + +group("qtwebengine_resources") { + deps = [ + "//chrome/app:generated_resources", + "//components/resources:components_resources", + ":qtwebengine_repack_resources", + ":qtwebengine_repack_resources_100", + ":qtwebengine_repack_resources_200", + ":qtwebengine_repack_resources_devtools", + ":qtwebengine_repack_locales_pack" + ] +} + +repack("qtwebengine_repack_resources") { + sources = [ + "$root_gen_dir/blink/public/resources/blink_resources.pak", + "$root_gen_dir/components/components_resources.pak", + "$root_gen_dir/content/content_resources.pak", + "$root_gen_dir/net/net_resources.pak", + "$root_gen_dir/ui/resources/webui_resources.pak", + ] + output = "$root_out_dir/qtwebengine_resources.pak" + deps = [ + "//components/resources:components_resources_grit", + "//content:resources_grit", + "//net:net_resources_grit", + "//third_party/WebKit/public:resources_grit", + "//ui/resources:webui_resources_grd_grit", + ] +} + +repack("qtwebengine_repack_resources_100") { + sources = [ + "$root_gen_dir/ui/resources/ui_resources_100_percent.pak", + "$root_gen_dir/components/components_resources_100_percent.pak", + "$root_gen_dir/content/app/resources/content_resources_100_percent.pak", + "$root_gen_dir/chrome/renderer_resources_100_percent.pak", + "$root_gen_dir/blink/public/resources/blink_image_resources_100_percent.pak", + ] + output = "$root_out_dir/qtwebengine_resources_100p.pak" + deps = [ + "//third_party/WebKit/public:image_resources_grit", + "//chrome/renderer:resources_grit", + "//components/resources:components_scaled_resources_grit", + "//content/app/resources:resources_grit", + "//ui/resources:ui_resources_grd_grit" + ] +} + +repack("qtwebengine_repack_resources_200") { + sources = [ + "$root_gen_dir/ui/resources/ui_resources_200_percent.pak", + "$root_gen_dir/components/components_resources_200_percent.pak", + "$root_gen_dir/content/app/resources/content_resources_200_percent.pak", + "$root_gen_dir/chrome/renderer_resources_200_percent.pak", + "$root_gen_dir/blink/public/resources/blink_image_resources_200_percent.pak", + ] + output = "$root_out_dir/qtwebengine_resources_200p.pak" + deps = [ + "//third_party/WebKit/public:image_resources_grit", + "//chrome/renderer:resources_grit", + "//components/resources:components_scaled_resources_grit", + "//content/app/resources:resources_grit", + "//ui/resources:ui_resources_grd_grit" + ] +} + +repack("qtwebengine_repack_resources_devtools") { + sources = [ + "$root_gen_dir/blink/devtools_resources.pak", + ] + output = "$root_out_dir/qtwebengine_devtools_resources.pak" + deps = [ + "//content/browser/devtools:devtools_resources_grit" + ] +} + +chrome_repack_locales("qtwebengine_repack_locales_pack") { + input_locales = locales + output_dir_name = "qtwebengine_locales" + output_locales = locales +} + diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni new file mode 100644 index 000000000..2d3503e98 --- /dev/null +++ b/src/core/qtwebengine_sources.gni @@ -0,0 +1,128 @@ +source_set("qtwebengine_sources") { + include_dirs = [ + "//skia/config", + "//third_party/skia/include/core" + ] + deps = [] + sources = [ + "//chrome/browser/media/desktop_media_list.h", + "//chrome/browser/media/desktop_streams_registry.cc", + "//chrome/browser/media/desktop_streams_registry.h", + "//chrome/common/chrome_switches.cc", + "//chrome/common/chrome_switches.h", + "//components/prefs/testing_pref_store.cc", + "//components/prefs/testing_pref_store.h", + "//extensions/common/constants.cc", + "//extensions/common/constants.h", + "//extensions/common/url_pattern.cc", + "//extensions/common/url_pattern.h", + ] + + if (enable_plugins) { + sources += [ + "//chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.cc", + "//chrome/browser/renderer_host/pepper/pepper_flash_clipboard_message_filter.h", + "//chrome/renderer/pepper/pepper_flash_font_file_host.cc", + "//chrome/renderer/pepper/pepper_flash_font_file_host.h", + "//chrome/renderer/pepper/pepper_shared_memory_message_filter.cc", + "//chrome/renderer/pepper/pepper_shared_memory_message_filter.h", + ] + + deps += [ + # Need to depend on //content/ppapi_plugin, which is private, thus depending on parent. + "//content", + ] + } + + if (enable_spellcheck) { + sources += [ + "//chrome/browser/spellchecker/feedback.cc", + "//chrome/browser/spellchecker/feedback.h", + "//chrome/browser/spellchecker/feedback_sender.cc", + "//chrome/browser/spellchecker/feedback_sender.h", + "//chrome/browser/spellchecker/misspelling.cc", + "//chrome/browser/spellchecker/misspelling.h", + "//chrome/browser/spellchecker/spellcheck_action.cc", + "//chrome/browser/spellchecker/spellcheck_action.h", + "//chrome/browser/spellchecker/spellcheck_custom_dictionary.cc", + "//chrome/browser/spellchecker/spellcheck_custom_dictionary.h", + "//chrome/browser/spellchecker/spellcheck_factory.cc", + "//chrome/browser/spellchecker/spellcheck_factory.h", + "//chrome/browser/spellchecker/spellcheck_host_metrics.cc", + "//chrome/browser/spellchecker/spellcheck_host_metrics.h", + "//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc", + "//chrome/browser/spellchecker/spellcheck_hunspell_dictionary.h", + "//chrome/browser/spellchecker/spellcheck_message_filter.cc", + "//chrome/browser/spellchecker/spellcheck_message_filter.h", + "//chrome/browser/spellchecker/spellcheck_platform_mac.mm", + "//chrome/browser/spellchecker/spellcheck_service.cc", + "//chrome/browser/spellchecker/spellcheck_service.h", + "//chrome/browser/spellchecker/spelling_service_client.cc", + "//chrome/browser/spellchecker/spelling_service_client.h", + "//chrome/browser/spellchecker/word_trimmer.cc", + "//chrome/browser/spellchecker/word_trimmer.h", + "//chrome/common/common_message_generator.cc", + "//chrome/common/pref_names.cc", + "//chrome/common/pref_names.h", + "//chrome/common/spellcheck_bdict_language.h", + "//chrome/common/spellcheck_common.cc", + "//chrome/common/spellcheck_common.h", + "//chrome/common/spellcheck_marker.h", + "//chrome/common/spellcheck_messages.h", + "//chrome/common/spellcheck_result.h", + "//chrome/renderer/spellchecker/custom_dictionary_engine.cc", + "//chrome/renderer/spellchecker/custom_dictionary_engine.h", + "//chrome/renderer/spellchecker/hunspell_engine.cc", + "//chrome/renderer/spellchecker/hunspell_engine.h", + "//chrome/renderer/spellchecker/spellcheck.cc", + "//chrome/renderer/spellchecker/spellcheck.h", + "//chrome/renderer/spellchecker/spellcheck_language.cc", + "//chrome/renderer/spellchecker/spellcheck_language.h", + "//chrome/renderer/spellchecker/spellcheck_provider.cc", + "//chrome/renderer/spellchecker/spellcheck_provider.h", + "//chrome/renderer/spellchecker/spellcheck_worditerator.cc", + "//chrome/renderer/spellchecker/spellcheck_worditerator.h", + "//chrome/renderer/spellchecker/spelling_engine.h", + ] + include_dirs += [ + "//third_party/WebKit" + ] + deps += [ + "//third_party/icu", + "//third_party/hunspell", + "//chrome/tools/convert_dict" + ] + + if (is_mac && use_browser_spellchecker) { + sources += [ + "//chrome/browser/spellchecker/spellcheck_message_filter_platform.h", + "//chrome/browser/spellchecker/spellcheck_message_filter_platform_mac.cc", + ] + } + } + + if (enable_basic_printing || enable_print_preview) { + sources += [ + "//chrome/browser/printing/printer_query.cc", + "//chrome/browser/printing/printer_query.h", + "//chrome/browser/printing/print_job.cc", + "//chrome/browser/printing/print_job.h", + "//chrome/browser/printing/print_job_manager.cc", + "//chrome/browser/printing/print_job_manager.h", + "//chrome/browser/printing/print_job_worker.cc", + "//chrome/browser/printing/print_job_worker.h", + "//chrome/browser/printing/print_job_worker_owner.cc", + "//chrome/browser/printing/print_job_worker_owner.h", + ] + } + + if (enable_pdf) { + deps += [ + "//pdf", + "//components/printing/browser", + "//components/printing/renderer", + ] + } + +} + diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index fef3831e3..280a0475d 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -116,7 +116,7 @@ static inline Qt::InputMethodHints toQtInputMethodHints(ui::TextInputType inputT case ui::TEXT_INPUT_TYPE_SEARCH: return Qt::ImhPreferLowercase | Qt::ImhNoAutoUppercase; case ui::TEXT_INPUT_TYPE_PASSWORD: - return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase; + return Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText; case ui::TEXT_INPUT_TYPE_EMAIL: return Qt::ImhEmailCharactersOnly; case ui::TEXT_INPUT_TYPE_NUMBER: @@ -575,6 +575,9 @@ void RenderWidgetHostViewQt::TextInputStateChanged(const content::TextInputState { m_currentInputType = params.type; m_delegate->inputMethodStateChanged(params.type != ui::TEXT_INPUT_TYPE_NONE); + m_delegate->setInputMethodHints(toQtInputMethodHints(params.type)); + + m_surroundingText = QString::fromStdString(params.value); } void RenderWidgetHostViewQt::ImeCancelComposition() @@ -838,7 +841,7 @@ QVariant RenderWidgetHostViewQt::inputMethodQuery(Qt::InputMethodQuery query) co case Qt::ImAnchorPosition: return static_cast<uint>(m_anchorPositionWithinSelection); case Qt::ImSurroundingText: - return toQt(selection_text_); + return m_surroundingText; case Qt::ImCurrentSelection: return toQt(GetSelectedText()); case Qt::ImMaximumTextLength: @@ -971,7 +974,13 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) } else { if (ev->type() == QEvent::KeyRelease) { m_receivedEmptyImeText = false; - m_host->ImeConfirmComposition(toString16(ev->text()), gfx::Range::InvalidRange(), + m_host->ImeSetComposition(toString16(ev->text()), + std::vector<blink::WebCompositionUnderline>(), + gfx::Range::InvalidRange(), + gfx::Range::InvalidRange().start(), + gfx::Range::InvalidRange().end()); + m_host->ImeConfirmComposition(base::string16(), + gfx::Range::InvalidRange(), false); m_imeInProgress = false; } @@ -980,17 +989,16 @@ void RenderWidgetHostViewQt::handleKeyEvent(QKeyEvent *ev) } content::NativeWebKeyboardEvent webEvent = WebEventFactory::toWebKeyboardEvent(ev); - if (webEvent.type == blink::WebInputEvent::RawKeyDown && !ev->text().isEmpty()) { + bool keyDownTextInsertion = webEvent.type == blink::WebInputEvent::RawKeyDown && webEvent.text[0]; + webEvent.skip_in_browser = keyDownTextInsertion; + m_host->ForwardKeyboardEvent(webEvent); + + if (keyDownTextInsertion) { // Blink won't consume the RawKeyDown, but rather the Char event in this case. // Make sure to skip the former on the way back. The same os_event will be set on both of them. webEvent.skip_in_browser = true; - m_host->ForwardKeyboardEvent(webEvent); - - webEvent.skip_in_browser = false; webEvent.type = blink::WebInputEvent::Char; m_host->ForwardKeyboardEvent(webEvent); - } else { - m_host->ForwardKeyboardEvent(webEvent); } } @@ -1002,9 +1010,6 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) QString commitString = ev->commitString(); QString preeditString = ev->preeditString(); - int replacementStart = ev->replacementStart(); - int replacementLength = ev->replacementLength(); - int cursorPositionInPreeditString = -1; gfx::Range selectionRange = gfx::Range::InvalidRange(); @@ -1067,33 +1072,45 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) } } - gfx::Range replacementRange = (replacementLength > 0) ? gfx::Range(replacementStart, replacementStart + replacementLength) - : gfx::Range::InvalidRange(); + int replacementLength = ev->replacementLength(); + gfx::Range replacementRange = gfx::Range::InvalidRange(); - auto setCompositionForPreEditString = [&](){ + if (replacementLength > 0) + { + int start = ev->replacementStart(); + + if (start >= 0) + replacementRange = gfx::Range(start, start + replacementLength); + else if (m_surroundingText.length() + start >= 0) { + start = m_surroundingText.length() + start; + replacementRange = gfx::Range(start, start + replacementLength); + } + } + + auto setCompositionString = [&](const QString &compositionString){ ensureValidSelectionRange(); - m_host->ImeSetComposition(toString16(preeditString), + m_host->ImeSetComposition(toString16(compositionString), underlines, replacementRange, selectionRange.start(), selectionRange.end()); }; - if (!commitString.isEmpty()) { - m_host->ImeConfirmComposition(toString16(commitString), replacementRange, false); + if (!commitString.isEmpty() || replacementLength > 0) { + setCompositionString(commitString); + m_host->ImeConfirmComposition(base::string16(), gfx::Range::InvalidRange(), false); // We might get a commit string and a pre-edit string in a single event, which means // we need to confirm the last composition, and start a new composition. if (!preeditString.isEmpty()) { - setCompositionForPreEditString(); + setCompositionString(preeditString); m_imeInProgress = true; } else { m_imeInProgress = false; } - m_receivedEmptyImeText = false; - + m_receivedEmptyImeText = commitString.isEmpty(); } else if (!preeditString.isEmpty()) { - setCompositionForPreEditString(); + setCompositionString(preeditString); m_imeInProgress = true; m_receivedEmptyImeText = false; } else { @@ -1115,7 +1132,10 @@ void RenderWidgetHostViewQt::handleInputMethodEvent(QInputMethodEvent *ev) QGuiApplication::postEvent(qApp->focusObject(), eventCopy); } else { m_receivedEmptyImeText = false; - m_host->ImeCancelComposition(); + if (m_imeInProgress) { + m_imeInProgress = false; + m_host->ImeCancelComposition(); + } } } } diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 0b2d7bc9d..2f5d97b67 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -244,6 +244,8 @@ private: gfx::Vector2dF m_lastScrollOffset; gfx::SizeF m_lastContentsSize; + + QString m_surroundingText; }; } // namespace QtWebEngineCore diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h index 1e50c8f08..1e1234e72 100644 --- a/src/core/render_widget_host_view_qt_delegate.h +++ b/src/core/render_widget_host_view_qt_delegate.h @@ -112,6 +112,7 @@ public: virtual void resize(int width, int height) = 0; virtual void move(const QPoint &) = 0; virtual void inputMethodStateChanged(bool editorVisible) = 0; + virtual void setInputMethodHints(Qt::InputMethodHints hints) = 0; virtual void setClearColor(const QColor &color) = 0; }; diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 9de2085ba..2534286bf 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -348,7 +348,7 @@ WebContentsAdapterPrivate::WebContentsAdapterPrivate() , adapterClient(0) , nextRequestId(CallbackDirectory::ReservedCallbackIdsEnd) , lastFindRequestId(0) - , currentDropAction(Qt::IgnoreAction) + , currentDropAction(blink::WebDragOperationNone) , inDragUpdateLoop(false) , updateDragCursorMessagePollingTimer(new QTimer) { @@ -1153,6 +1153,18 @@ static QMimeData *mimeDataFromDropData(const content::DropData &dropData) return mimeData; } +static blink::WebDragOperationsMask toWeb(const Qt::DropActions action) +{ + int result = blink::WebDragOperationNone; + if (action & Qt::CopyAction) + result |= blink::WebDragOperationCopy; + if (action & Qt::LinkAction) + result |= blink::WebDragOperationLink; + if (action & Qt::MoveAction) + result |= blink::WebDragOperationMove; + return static_cast<blink::WebDragOperationsMask>(result); +} + void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropData &dropData, Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset) @@ -1169,7 +1181,7 @@ void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropD d->currentDropData->file_contents.clear(); d->currentDropData->file_description_filename.clear(); - d->currentDropAction = Qt::IgnoreAction; + d->currentDropAction = blink::WebDragOperationNone; QDrag *drag = new QDrag(dragSource); // will be deleted by Qt's DnD implementation bool dValid = true; QMetaObject::Connection onDestroyed = QObject::connect(dragSource, &QObject::destroyed, [&dValid](){ @@ -1192,25 +1204,17 @@ void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropD if (dValid) { if (d->webContents) { content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); - if (rvh) + if (rvh) { + rvh->DragSourceEndedAt(d->lastDragClientPos.x(), d->lastDragClientPos.y(), + d->lastDragScreenPos.x(), d->lastDragScreenPos.y(), + d->currentDropAction); rvh->DragSourceSystemDragEnded(); + } } d->currentDropData.reset(); } } -static blink::WebDragOperationsMask toWeb(const Qt::DropActions action) -{ - int result = blink::WebDragOperationNone; - if (action & Qt::CopyAction) - result |= blink::WebDragOperationCopy; - if (action & Qt::LinkAction) - result |= blink::WebDragOperationLink; - if (action & Qt::MoveAction) - result |= blink::WebDragOperationMove; - return static_cast<blink::WebDragOperationsMask>(result); -} - static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeData *mimeData) { Q_ASSERT(dropData->filenames.empty()); @@ -1246,12 +1250,51 @@ void WebContentsAdapter::enterDrag(QDragEnterEvent *e, const QPoint &screenPos) flagsFromModifiers(e->keyboardModifiers())); } +Qt::DropAction toQt(blink::WebDragOperation op) +{ + if (op & blink::WebDragOperationCopy) + return Qt::CopyAction; + if (op & blink::WebDragOperationLink) + return Qt::LinkAction; + if (op & blink::WebDragOperationMove || op & blink::WebDragOperationDelete) + return Qt::MoveAction; + return Qt::IgnoreAction; +} + +static int toWeb(Qt::MouseButtons buttons) +{ + int result = 0; + if (buttons & Qt::LeftButton) + result |= blink::WebInputEvent::LeftButtonDown; + if (buttons & Qt::RightButton) + result |= blink::WebInputEvent::RightButtonDown; + if (buttons & Qt::MiddleButton) + result |= blink::WebInputEvent::MiddleButtonDown; + return result; +} + +static int toWeb(Qt::KeyboardModifiers modifiers) +{ + int result = 0; + if (modifiers & Qt::ShiftModifier) + result |= blink::WebInputEvent::ShiftKey; + if (modifiers & Qt::ControlModifier) + result |= blink::WebInputEvent::ControlKey; + if (modifiers & Qt::AltModifier) + result |= blink::WebInputEvent::AltKey; + if (modifiers & Qt::MetaModifier) + result |= blink::WebInputEvent::MetaKey; + return result; +} + Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const QPoint &screenPos) { Q_D(WebContentsAdapter); content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); - rvh->DragTargetDragOver(toGfx(e->pos()), toGfx(screenPos), toWeb(e->possibleActions()), - blink::WebInputEvent::LeftButtonDown); + d->lastDragClientPos = toGfx(e->pos()); + d->lastDragScreenPos = toGfx(screenPos); + rvh->DragTargetDragOver(d->lastDragClientPos, d->lastDragScreenPos, toWeb(e->possibleActions()), + toWeb(e->mouseButtons()) | toWeb(e->keyboardModifiers())); base::MessageLoop *currentMessageLoop = base::MessageLoop::current(); DCHECK(currentMessageLoop); @@ -1273,13 +1316,13 @@ Qt::DropAction WebContentsAdapter::updateDragPosition(QDragMoveEvent *e, const Q loop.Run(); d->updateDragCursorMessagePollingTimer->stop(); - return d->currentDropAction; + return toQt(d->currentDropAction); } -void WebContentsAdapter::updateDragAction(Qt::DropAction action) +void WebContentsAdapter::updateDragAction(int action) { Q_D(WebContentsAdapter); - d->currentDropAction = action; + d->currentDropAction = static_cast<blink::WebDragOperation>(action); finishDragUpdate(); } @@ -1298,7 +1341,9 @@ void WebContentsAdapter::endDragging(const QPoint &clientPos, const QPoint &scre finishDragUpdate(); content::RenderViewHost *rvh = d->webContents->GetRenderViewHost(); rvh->FilterDropData(d->currentDropData.get()); - rvh->DragTargetDrop(*d->currentDropData, toGfx(clientPos), toGfx(screenPos), 0); + d->lastDragClientPos = toGfx(clientPos); + d->lastDragScreenPos = toGfx(screenPos); + rvh->DragTargetDrop(*d->currentDropData, d->lastDragClientPos, d->lastDragScreenPos, 0); d->currentDropData.reset(); } @@ -1398,4 +1443,15 @@ bool WebContentsAdapter::canViewSource() return d->webContents->GetController().CanViewSource(); } +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::UnknownDisposition, WindowOpenDisposition::UNKNOWN) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::CurrentTabDisposition, WindowOpenDisposition::CURRENT_TAB) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::SingletonTabDisposition, WindowOpenDisposition::SINGLETON_TAB) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::NewForegroundTabDisposition, WindowOpenDisposition::NEW_FOREGROUND_TAB) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::NewBackgroundTabDisposition, WindowOpenDisposition::NEW_BACKGROUND_TAB) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::NewPopupDisposition, WindowOpenDisposition::NEW_POPUP) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::NewWindowDisposition, WindowOpenDisposition::NEW_WINDOW) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::SaveToDiskDisposition, WindowOpenDisposition::SAVE_TO_DISK) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::OffTheRecordDisposition, WindowOpenDisposition::OFF_THE_RECORD) +ASSERT_ENUMS_MATCH(WebContentsAdapterClient::IgnoreActionDisposition, WindowOpenDisposition::IGNORE_ACTION) + } // namespace QtWebEngineCore diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h index cb7f9b461..0accd3be5 100644 --- a/src/core/web_contents_adapter.h +++ b/src/core/web_contents_adapter.h @@ -168,7 +168,7 @@ public: Qt::DropActions allowedActions, const QPixmap &pixmap, const QPoint &offset); void enterDrag(QDragEnterEvent *e, const QPoint &screenPos); Qt::DropAction updateDragPosition(QDragMoveEvent *e, const QPoint &screenPos); - void updateDragAction(Qt::DropAction action); + void updateDragAction(int action); void finishDragUpdate(); void endDragging(const QPoint &clientPos, const QPoint &screenPos); void leaveDrag(); diff --git a/src/core/web_contents_adapter_p.h b/src/core/web_contents_adapter_p.h index 23a1aaef4..9503b4401 100644 --- a/src/core/web_contents_adapter_p.h +++ b/src/core/web_contents_adapter_p.h @@ -55,6 +55,8 @@ #include <base/callback.h> #include "base/memory/ref_counted.h" +#include <ui/gfx/geometry/point.h> +#include <third_party/WebKit/public/platform/WebDragOperation.h> #include <QScopedPointer> #include <QSharedPointer> @@ -93,8 +95,10 @@ public: quint64 nextRequestId; int lastFindRequestId; std::unique_ptr<content::DropData> currentDropData; - Qt::DropAction currentDropAction; + blink::WebDragOperation currentDropAction; bool inDragUpdateLoop; + gfx::Point lastDragClientPos; + gfx::Point lastDragScreenPos; base::Closure dragUpdateLoopQuitClosure; QScopedPointer<QTimer> updateDragCursorMessagePollingTimer; }; diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp index 0c4cf29d3..24c4e198f 100644 --- a/src/core/web_contents_view_qt.cpp +++ b/src/core/web_contents_view_qt.cpp @@ -203,17 +203,6 @@ Qt::DropActions toQtDropActions(blink::WebDragOperationsMask ops) return result; } -Qt::DropAction toQt(blink::WebDragOperation op) -{ - if (op == blink::WebDragOperationCopy) - return Qt::CopyAction; - if (op == blink::WebDragOperationLink) - return Qt::LinkAction; - if (op == blink::WebDragOperationMove || op == blink::WebDragOperationDelete) - return Qt::MoveAction; - return Qt::IgnoreAction; -} - void WebContentsViewQt::StartDragging(const content::DropData &drop_data, blink::WebDragOperationsMask allowed_ops, const gfx::ImageSkia &image, @@ -235,7 +224,7 @@ void WebContentsViewQt::StartDragging(const content::DropData &drop_data, void WebContentsViewQt::UpdateDragCursor(blink::WebDragOperation dragOperation) { - m_client->webContentsAdapter()->updateDragAction(toQt(dragOperation)); + m_client->webContentsAdapter()->updateDragAction(dragOperation); } void WebContentsViewQt::TakeFocus(bool reverse) diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp index 4f5023376..9681ad629 100644 --- a/src/core/web_event_factory.cpp +++ b/src/core/web_event_factory.cpp @@ -1259,5 +1259,14 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e const ushort* text = ev->text().utf16(); memcpy(&webKitEvent.text, text, std::min(sizeof(webKitEvent.text), size_t(ev->text().length() * 2))); memcpy(&webKitEvent.unmodifiedText, text, std::min(sizeof(webKitEvent.unmodifiedText), size_t(ev->text().length() * 2))); + + if (webKitEvent.windowsKeyCode == VK_RETURN) { + // This is the same behavior as GTK: + // We need to treat the enter key as a key press of character \r. This + // is apparently just how webkit handles it and what it expects. + webKitEvent.unmodifiedText[0] = '\r'; + webKitEvent.text[0] = webKitEvent.unmodifiedText[0]; + } + return webKitEvent; } diff --git a/src/src.pro b/src/src.pro index 26abd52cc..7f8b39cd6 100644 --- a/src/src.pro +++ b/src/src.pro @@ -7,37 +7,32 @@ webengine_plugin.subdir = webengine/plugin webengine_plugin.target = sub-webengine-plugin webengine_plugin.depends = webengine -SUBDIRS += core +SUBDIRS += core \ + process \ + webengine \ + webengine_plugin \ + plugins -!use?(gn) { - SUBDIRS += process \ - webengine \ - webengine_plugin \ - plugins +use?(spellchecker):!use?(native_spellchecker):!cross_compile { + SUBDIRS += qwebengine_convert_dict + qwebengine_convert_dict.subdir = tools/qwebengine_convert_dict + qwebengine_convert_dict.depends = core +} - # allow only desktop builds of qwebengine_convert_dict - contains(WEBENGINE_CONFIG, use_spellchecker):!contains(WEBENGINE_CONFIG, use_native_spellchecker):!cross_compile { - SUBDIRS += qwebengine_convert_dict - qwebengine_convert_dict.subdir = tools/qwebengine_convert_dict - qwebengine_convert_dict.depends = core - } +isQMLTestSupportApiEnabled() { + webengine_testsupport_plugin.subdir = webengine/plugin/testsupport + webengine_testsupport_plugin.target = sub-webengine-testsupport-plugin + webengine_testsupport_plugin.depends = webengine + SUBDIRS += webengine_testsupport_plugin +} - isQMLTestSupportApiEnabled() { - webengine_testsupport_plugin.subdir = webengine/plugin/testsupport - webengine_testsupport_plugin.target = sub-webengine-testsupport-plugin - webengine_testsupport_plugin.depends = webengine - SUBDIRS += webengine_testsupport_plugin - } +!contains(WEBENGINE_CONFIG, no_ui_delegates) { + SUBDIRS += webengine/ui \ + webengine/ui2 +} - # FIXME: We probably want a bit more control over config options to tweak what to build/ship or not. - # Another example of where this could be necessary is to make it easy to build proprietery codecs support. - !contains(WEBENGINE_CONFIG, no_ui_delegates) { - SUBDIRS += webengine/ui \ - webengine/ui2 - } - qtHaveModule(widgets) { - SUBDIRS += webenginewidgets - plugins.depends = webenginewidgets - } +qtHaveModule(widgets) { + SUBDIRS += webenginewidgets + plugins.depends = webenginewidgets } diff --git a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro index 715081b5f..7bece36cd 100644 --- a/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro +++ b/src/tools/qwebengine_convert_dict/qwebengine_convert_dict.pro @@ -1,12 +1,31 @@ option(host_build) # Look for linking information produced by gyp for our target according to core_generated.gyp -!include($$OUT_PWD/../../core/$$getConfigDir()/convert_dict_linking.pri) { - error("Could not find the linking information that gyp should have generated.") +use?(gn): linking_pri = $$OUT_PWD/../../core/$$getConfigDir()/convert_dict.pri +else: linking_pri = $$OUT_PWD/../../core/$$getConfigDir()/convert_dict_linking.pri + +!include($$linking_pri) { + error("Could not find the linking information that gyp/gn should have generated.") } -# skip dummy main.cpp file -OBJECTS = +use?(gn){ + isEmpty(NINJA_OBJECTS): error("Missing object files from QtWebEngineCore linking pri.") + isEmpty(NINJA_LFLAGS): error("Missing linker flags from QtWebEngineCore linking pri") + isEmpty(NINJA_ARCHIVES): error("Missing archive files from QtWebEngineCore linking pri") + isEmpty(NINJA_LIBS): error("Missing library files from QtWebEngineCore linking pri") + OBJECTS = $$eval($$list($$NINJA_OBJECTS)) + linux { + LIBS_PRIVATE = -Wl,--start-group $$NINJA_ARCHIVES -Wl,--end-group + } else { + LIBS_PRIVATE = $$NINJA_ARCHIVES + } + LIBS_PRIVATE += $$NINJA_LIB_DIRS $$NINJA_LIBS + QMAKE_LFLAGS += $$NINJA_LFLAGS + POST_TARGETDEPS += $$NINJA_TARGETDEPS +} else { + # skip dummy main.cpp file + OBJECTS = +} # Fixme: -Werror=unused-parameter in core QMAKE_CXXFLAGS_WARN_ON = diff --git a/src/webengine/api/qquickwebengineprofile.cpp b/src/webengine/api/qquickwebengineprofile.cpp index 871428f33..162dbe1d7 100644 --- a/src/webengine/api/qquickwebengineprofile.cpp +++ b/src/webengine/api/qquickwebengineprofile.cpp @@ -42,6 +42,7 @@ #include "qquickwebenginedownloaditem_p.h" #include "qquickwebenginedownloaditem_p_p.h" #include "qquickwebengineprofile_p.h" +#include "qquickwebenginescript_p.h" #include "qquickwebenginesettings_p.h" #include "qwebenginecookiestore.h" @@ -49,6 +50,7 @@ #include "browser_context_adapter.h" #include <qtwebenginecoreglobal.h> +#include "renderer_host/user_resource_controller_host.h" #include "web_engine_settings.h" using QtWebEngineCore::BrowserContextAdapter; @@ -229,6 +231,38 @@ void QQuickWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info } } +void QQuickWebEngineProfilePrivate::userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script) +{ + Q_ASSERT(p && p->data); + QQuickWebEngineProfilePrivate *d = static_cast<QQuickWebEngineProfilePrivate *>(p->data); + QtWebEngineCore::UserResourceControllerHost *resourceController = d->browserContext()->userResourceController(); + d->m_userScripts.append(script); + script->d_func()->bind(resourceController); +} + +int QQuickWebEngineProfilePrivate::userScripts_count(QQmlListProperty<QQuickWebEngineScript> *p) +{ + Q_ASSERT(p && p->data); + QQuickWebEngineProfilePrivate *d = static_cast<QQuickWebEngineProfilePrivate *>(p->data); + return d->m_userScripts.count(); +} + +QQuickWebEngineScript *QQuickWebEngineProfilePrivate::userScripts_at(QQmlListProperty<QQuickWebEngineScript> *p, int idx) +{ + Q_ASSERT(p && p->data); + QQuickWebEngineProfilePrivate *d = static_cast<QQuickWebEngineProfilePrivate *>(p->data); + return d->m_userScripts.at(idx); +} + +void QQuickWebEngineProfilePrivate::userScripts_clear(QQmlListProperty<QQuickWebEngineScript> *p) +{ + Q_ASSERT(p && p->data); + QQuickWebEngineProfilePrivate *d = static_cast<QQuickWebEngineProfilePrivate *>(p->data); + QtWebEngineCore::UserResourceControllerHost *resourceController = d->browserContext()->userResourceController(); + resourceController->clearAllScripts(NULL); + d->m_userScripts.clear(); +} + /*! \qmltype WebEngineProfile \instantiates QQuickWebEngineProfile @@ -851,4 +885,33 @@ QQuickWebEngineSettings *QQuickWebEngineProfile::settings() const return d->settings(); } +/*! + \qmlproperty list<WebEngineScript> WebEngineProfile::userScripts + \since 1.5 + + Returns the collection of WebEngineScripts that are injected into all pages that share + this profile. + + \sa WebEngineScript +*/ + +/*! + \property QQuickWebEngineProfile::userScripts + \since 5.9 + + \brief the collection of scripts that are injected into all pages that share + this profile. + + \sa QQuickWebEngineScript, QQmlListReference +*/ +QQmlListProperty<QQuickWebEngineScript> QQuickWebEngineProfile::userScripts() +{ + Q_D(QQuickWebEngineProfile); + return QQmlListProperty<QQuickWebEngineScript>(this, d, + d->userScripts_append, + d->userScripts_count, + d->userScripts_at, + d->userScripts_clear); +} + QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebengineprofile.h b/src/webengine/api/qquickwebengineprofile.h index d0d925930..0155c954a 100644 --- a/src/webengine/api/qquickwebengineprofile.h +++ b/src/webengine/api/qquickwebengineprofile.h @@ -46,6 +46,7 @@ #include <QtCore/QObject> #include <QtCore/QScopedPointer> #include <QtCore/QString> +#include <QtQml/QQmlListProperty> namespace QtWebEngineCore { class BrowserContextAdapter; @@ -55,6 +56,7 @@ QT_BEGIN_NAMESPACE class QQuickWebEngineDownloadItem; class QQuickWebEngineProfilePrivate; +class QQuickWebEngineScript; class QQuickWebEngineSettings; class QWebEngineCookieStore; class QWebEngineUrlRequestInterceptor; @@ -73,6 +75,7 @@ class Q_WEBENGINE_EXPORT QQuickWebEngineProfile : public QObject { Q_PROPERTY(int httpCacheMaximumSize READ httpCacheMaximumSize WRITE setHttpCacheMaximumSize NOTIFY httpCacheMaximumSizeChanged FINAL) Q_PROPERTY(QStringList spellCheckLanguages READ spellCheckLanguages WRITE setSpellCheckLanguages NOTIFY spellCheckLanguagesChanged FINAL REVISION 3) Q_PROPERTY(bool spellCheckEnabled READ isSpellCheckEnabled WRITE setSpellCheckEnabled NOTIFY spellCheckEnabledChanged FINAL REVISION 3) + Q_PROPERTY(QQmlListProperty<QQuickWebEngineScript> userScripts READ userScripts FINAL REVISION 4) public: QQuickWebEngineProfile(QObject *parent = Q_NULLPTR); @@ -136,6 +139,8 @@ public: void setSpellCheckEnabled(bool enabled); bool isSpellCheckEnabled() const; + QQmlListProperty<QQuickWebEngineScript> userScripts(); + static QQuickWebEngineProfile *defaultProfile(); Q_SIGNALS: diff --git a/src/webengine/api/qquickwebengineprofile_p.h b/src/webengine/api/qquickwebengineprofile_p.h index 1ba1eb53f..1828f8085 100644 --- a/src/webengine/api/qquickwebengineprofile_p.h +++ b/src/webengine/api/qquickwebengineprofile_p.h @@ -80,12 +80,19 @@ public: void downloadRequested(DownloadItemInfo &info) Q_DECL_OVERRIDE; void downloadUpdated(const DownloadItemInfo &info) Q_DECL_OVERRIDE; + // QQmlListPropertyHelpers + static void userScripts_append(QQmlListProperty<QQuickWebEngineScript> *p, QQuickWebEngineScript *script); + static int userScripts_count(QQmlListProperty<QQuickWebEngineScript> *p); + static QQuickWebEngineScript *userScripts_at(QQmlListProperty<QQuickWebEngineScript> *p, int idx); + static void userScripts_clear(QQmlListProperty<QQuickWebEngineScript> *p); + private: friend class QQuickWebEngineViewPrivate; QQuickWebEngineProfile *q_ptr; QScopedPointer<QQuickWebEngineSettings> m_settings; QSharedPointer<QtWebEngineCore::BrowserContextAdapter> m_browserContextRef; QMap<quint32, QPointer<QQuickWebEngineDownloadItem> > m_ongoingDownloads; + QList<QQuickWebEngineScript *> m_userScripts; }; QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginescript.cpp b/src/webengine/api/qquickwebenginescript.cpp index 5d5173144..590faf4f3 100644 --- a/src/webengine/api/qquickwebenginescript.cpp +++ b/src/webengine/api/qquickwebenginescript.cpp @@ -37,8 +37,8 @@ ** ****************************************************************************/ +#include "qquickwebenginescript.h" #include "qquickwebenginescript_p.h" -#include "qquickwebenginescript_p_p.h" #include <QQmlFile> #include <QtCore/QDebug> @@ -48,6 +48,58 @@ using QtWebEngineCore::UserScript; +QT_BEGIN_NAMESPACE + +/*! + \class QQuickWebEngineScript + \brief Enables the injection of scripts in the JavaScript engine. + \inmodule QtWebEngine + \since 5.9 + + The QQuickWebEngineScript type enables the programmatic injection of so called \e {user scripts} in + the JavaScript engine at different points, determined by injectionPoint, during the loading of + web content. + + Scripts can be executed either in the main JavaScript \e world, along with the rest of the + JavaScript coming from the web contents, or in their own isolated world. While the DOM of the + page can be accessed from any world, JavaScript variables of a function defined in one world are + not accessible from a different one. The worldId property provides some predefined IDs for this + purpose. +*/ + +/*! + \enum QQuickWebEngineScript::InjectionPoint + + The point in the loading process at which the script will be executed. + + \value DocumentCreation + The script will be executed as soon as the document is created. This is not suitable for + any DOM operation. + \value DocumentReady + The script will run as soon as the DOM is ready. This is equivalent to the + \c DOMContentLoaded event firing in JavaScript. + \value Deferred + The script will run when the page load finishes, or 500 ms after the document is ready, + whichever comes first. +*/ + +/*! + \enum QQuickWebEngineScript::ScriptWorldId + + The world ID defining which isolated world the script is executed in. + + \value MainWorld + The world used by the page's web contents. It can be useful in order to expose custom + functionality to web contents in certain scenarios. + \value ApplicationWorld + The default isolated world used for application level functionality implemented in + JavaScript. + \value UserWorld + The first isolated world to be used by scripts set by users if the application is not + making use of more worlds. As a rule of thumb, if that functionality is exposed to the + application users, each individual script should probably get its own isolated world. +*/ + /*! \qmltype WebEngineScript \instantiates QQuickWebEngineScript @@ -72,16 +124,26 @@ using QtWebEngineCore::UserScript; attached to the web view. */ -QQuickWebEngineScript::QQuickWebEngineScript() - : d_ptr(new QQuickWebEngineScriptPrivate) +/*! + Constructs a new QQuickWebEngineScript with the parent \a parent. +*/ +QQuickWebEngineScript::QQuickWebEngineScript(QObject *parent) + : QObject(parent) + , d_ptr(new QQuickWebEngineScriptPrivate) { d_ptr->q_ptr = this; } +/*! + \internal +*/ QQuickWebEngineScript::~QQuickWebEngineScript() { } +/*! + Returns the script object as string. +*/ QString QQuickWebEngineScript::toString() const { Q_D(const QQuickWebEngineScript); @@ -106,6 +168,14 @@ QString QQuickWebEngineScript::toString() const } /*! + \property QQuickWebEngineScript::name + \brief The name of the script. + + Can be useful to retrieve a particular script from + QQuickWebEngineProfile::userScripts. +*/ + +/*! \qmlproperty string WebEngineScript::name The name of the script. Can be useful to retrieve a particular script from @@ -118,6 +188,20 @@ QString QQuickWebEngineScript::name() const } /*! + \property QQuickWebEngineScript::sourceUrl + \brief The remote source location of the user script (if any). + + Unlike \l sourceCode, this property allows referring to user scripts that + are not already loaded in memory, for instance, when stored on disk. + + Setting this property will change the \l sourceCode of the script. + + \note At present, only file-based sources are supported. + + \sa QQuickWebEngineScript::sourceCode +*/ + +/*! \qmlproperty url WebEngineScript::sourceUrl This property holds the remote source location of the user script (if any). @@ -138,6 +222,13 @@ QUrl QQuickWebEngineScript::sourceUrl() const } /*! + \property QQuickWebEngineScript::sourceCode + \brief The JavaScript source code of the user script. + + \sa QQuickWebEngineScript::sourceUrl +*/ + +/*! \qmlproperty string WebEngineScript::sourceCode This property holds the JavaScript source code of the user script. @@ -155,6 +246,13 @@ ASSERT_ENUMS_MATCH(QQuickWebEngineScript::DocumentReady, UserScript::DocumentLoa ASSERT_ENUMS_MATCH(QQuickWebEngineScript::DocumentCreation, UserScript::DocumentElementCreation) /*! + \property QQuickWebEngineScript::injectionPoint + \brief The point in the loading process at which the script will be executed. + + The default value is \c Deferred. +*/ + +/*! \qmlproperty enumeration WebEngineScript::injectionPoint The point in the loading process at which the script will be executed. @@ -177,6 +275,11 @@ QQuickWebEngineScript::InjectionPoint QQuickWebEngineScript::injectionPoint() co } /*! + \property QQuickWebEngineScript::worldId + \brief The world ID defining which isolated world the script is executed in. +*/ + +/*! \qmlproperty enumeration WebEngineScript::worldId The world ID defining which isolated world the script is executed in. @@ -199,6 +302,15 @@ QQuickWebEngineScript::ScriptWorldId QQuickWebEngineScript::worldId() const } /*! + \property QQuickWebEngineScript::runOnSubframes + \brief Whether the script is executed on every frame or only on the main frame. + + Set this property to \c true if the script is executed on every frame in the page, or \c false + if it is only run for the main frame. + The default value is \c{false}. +*/ + +/*! \qmlproperty int WebEngineScript::runOnSubframes Set this property to \c true if the script is executed on every frame in the page, or \c false @@ -211,21 +323,20 @@ bool QQuickWebEngineScript::runOnSubframes() const return d->coreScript.runsOnSubFrames(); } - -void QQuickWebEngineScript::setName(QString arg) +void QQuickWebEngineScript::setName(const QString &name) { Q_D(QQuickWebEngineScript); - if (arg == name()) + if (name == QQuickWebEngineScript::name()) return; d->aboutToUpdateUnderlyingScript(); - d->coreScript.setName(arg); - Q_EMIT nameChanged(arg); + d->coreScript.setName(name); + Q_EMIT nameChanged(name); } -void QQuickWebEngineScript::setSourceCode(QString arg) +void QQuickWebEngineScript::setSourceCode(const QString &code) { Q_D(QQuickWebEngineScript); - if (arg == sourceCode()) + if (code == sourceCode()) return; // setting the source directly resets the sourceUrl @@ -235,22 +346,22 @@ void QQuickWebEngineScript::setSourceCode(QString arg) } d->aboutToUpdateUnderlyingScript(); - d->coreScript.setSourceCode(arg); - Q_EMIT sourceCodeChanged(arg); + d->coreScript.setSourceCode(code); + Q_EMIT sourceCodeChanged(code); } -void QQuickWebEngineScript::setSourceUrl(QUrl arg) +void QQuickWebEngineScript::setSourceUrl(const QUrl &url) { Q_D(QQuickWebEngineScript); - if (arg == sourceUrl()) + if (url == sourceUrl()) return; - d->m_sourceUrl = arg; + d->m_sourceUrl = url; Q_EMIT sourceUrlChanged(d->m_sourceUrl); - QFile f(QQmlFile::urlToLocalFileOrQrc(arg)); + QFile f(QQmlFile::urlToLocalFileOrQrc(url)); if (!f.open(QIODevice::ReadOnly)) { - qWarning() << "Can't open user script " << arg; + qWarning() << "Can't open user script " << url; return; } @@ -260,36 +371,36 @@ void QQuickWebEngineScript::setSourceUrl(QUrl arg) Q_EMIT sourceCodeChanged(source); } -void QQuickWebEngineScript::setInjectionPoint(QQuickWebEngineScript::InjectionPoint arg) +void QQuickWebEngineScript::setInjectionPoint(QQuickWebEngineScript::InjectionPoint injectionPoint) { Q_D(QQuickWebEngineScript); - if (arg == injectionPoint()) + if (injectionPoint == QQuickWebEngineScript::injectionPoint()) return; d->aboutToUpdateUnderlyingScript(); - d->coreScript.setInjectionPoint(static_cast<UserScript::InjectionPoint>(arg)); - Q_EMIT injectionPointChanged(arg); + d->coreScript.setInjectionPoint(static_cast<UserScript::InjectionPoint>(injectionPoint)); + Q_EMIT injectionPointChanged(injectionPoint); } -void QQuickWebEngineScript::setWorldId(QQuickWebEngineScript::ScriptWorldId arg) +void QQuickWebEngineScript::setWorldId(QQuickWebEngineScript::ScriptWorldId scriptWorldId) { Q_D(QQuickWebEngineScript); - if (arg == worldId()) + if (scriptWorldId == worldId()) return; d->aboutToUpdateUnderlyingScript(); - d->coreScript.setWorldId(arg); - Q_EMIT worldIdChanged(arg); + d->coreScript.setWorldId(scriptWorldId); + Q_EMIT worldIdChanged(scriptWorldId); } -void QQuickWebEngineScript::setRunOnSubframes(bool arg) +void QQuickWebEngineScript::setRunOnSubframes(bool on) { Q_D(QQuickWebEngineScript); - if (arg == runOnSubframes()) + if (on == runOnSubframes()) return; d->aboutToUpdateUnderlyingScript(); - d->coreScript.setRunsOnSubFrames(arg); - Q_EMIT runOnSubframesChanged(arg); + d->coreScript.setRunsOnSubFrames(on); + Q_EMIT runOnSubframesChanged(on); } void QQuickWebEngineScript::timerEvent(QTimerEvent *e) @@ -327,3 +438,5 @@ void QQuickWebEngineScriptPrivate::aboutToUpdateUnderlyingScript() // Defer updates to the next event loop m_basicTimer.start(0, q); } + +QT_END_NAMESPACE diff --git a/src/webengine/api/qquickwebenginescript.h b/src/webengine/api/qquickwebenginescript.h new file mode 100644 index 000000000..2cd4fadf1 --- /dev/null +++ b/src/webengine/api/qquickwebenginescript.h @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef QQUICKWEBENGINESCRIPT_H +#define QQUICKWEBENGINESCRIPT_H + +#include <QtCore/qobject.h> +#include <QtCore/qurl.h> +#include <QtWebEngine/qtwebengineglobal.h> + +QT_BEGIN_NAMESPACE +class QQuickWebEngineScriptPrivate; +class QQuickWebEngineView; + +class Q_WEBENGINE_EXPORT QQuickWebEngineScript : public QObject +{ + Q_OBJECT + Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged) + Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl NOTIFY sourceUrlChanged) + Q_PROPERTY(QString sourceCode READ sourceCode WRITE setSourceCode NOTIFY sourceCodeChanged) + Q_PROPERTY(InjectionPoint injectionPoint READ injectionPoint WRITE setInjectionPoint NOTIFY injectionPointChanged) + Q_PROPERTY(ScriptWorldId worldId READ worldId WRITE setWorldId NOTIFY worldIdChanged) + Q_PROPERTY(bool runOnSubframes READ runOnSubframes WRITE setRunOnSubframes NOTIFY runOnSubframesChanged) + + +public: + enum InjectionPoint { + Deferred, + DocumentReady, + DocumentCreation + }; + Q_ENUM(InjectionPoint) + + enum ScriptWorldId { + MainWorld = 0, + ApplicationWorld, + UserWorld + }; + Q_ENUM(ScriptWorldId) + + QQuickWebEngineScript(QObject *parent = Q_NULLPTR); + ~QQuickWebEngineScript(); + Q_INVOKABLE QString toString() const; + + QString name() const; + QUrl sourceUrl() const; + QString sourceCode() const; + InjectionPoint injectionPoint() const; + ScriptWorldId worldId() const; + bool runOnSubframes() const; + + void setName(const QString &name); + void setSourceUrl(const QUrl &url); + void setSourceCode(const QString &code); + void setInjectionPoint(InjectionPoint injectionPoint); + void setWorldId(ScriptWorldId scriptWorldId); + void setRunOnSubframes(bool on); + +Q_SIGNALS: + void nameChanged(const QString &name); + void sourceUrlChanged(const QUrl &url); + void sourceCodeChanged(const QString &code); + void injectionPointChanged(InjectionPoint injectionPoint); + void worldIdChanged(ScriptWorldId scriptWorldId); + void runOnSubframesChanged(bool on); + +protected: + void timerEvent(QTimerEvent *e) override; + +private: + friend class QQuickWebEngineProfilePrivate; + friend class QQuickWebEngineViewPrivate; + Q_DECLARE_PRIVATE(QQuickWebEngineScript) + QScopedPointer<QQuickWebEngineScriptPrivate> d_ptr; +}; +QT_END_NAMESPACE + +#endif // QQUICKWEBENGINESCRIPT_H diff --git a/src/webengine/api/qquickwebenginescript_p.h b/src/webengine/api/qquickwebenginescript_p.h index 851ecd26b..30b47a654 100644 --- a/src/webengine/api/qquickwebenginescript_p.h +++ b/src/webengine/api/qquickwebenginescript_p.h @@ -51,75 +51,37 @@ // We mean it. // -#include <private/qtwebengineglobal_p.h> -#include <QtCore/QObject> -#include <QtCore/QUrl> +#include "qquickwebenginescript.h" -QT_BEGIN_NAMESPACE -class QQuickWebEngineScriptPrivate; -class QQuickWebEngineView; +#include <QtCore/QBasicTimer> +#include "user_script.h" +#include "web_contents_adapter.h" -class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineScript : public QObject -{ - Q_OBJECT - Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) - Q_PROPERTY(QUrl sourceUrl READ sourceUrl WRITE setSourceUrl NOTIFY sourceUrlChanged FINAL) - Q_PROPERTY(QString sourceCode READ sourceCode WRITE setSourceCode NOTIFY sourceCodeChanged FINAL) - Q_PROPERTY(InjectionPoint injectionPoint READ injectionPoint WRITE setInjectionPoint NOTIFY injectionPointChanged FINAL) - Q_PROPERTY(ScriptWorldId worldId READ worldId WRITE setWorldId NOTIFY worldIdChanged FINAL) - Q_PROPERTY(bool runOnSubframes READ runOnSubframes WRITE setRunOnSubframes NOTIFY runOnSubframesChanged FINAL) +namespace QtWebEngineCore { +class UserResourceControllerHost; +class WebContentsAdapter; +} // namespace +QT_BEGIN_NAMESPACE +class QQuickWebEngineScriptPrivate { public: - enum InjectionPoint { - Deferred, - DocumentReady, - DocumentCreation - }; - Q_ENUM(InjectionPoint) - - enum ScriptWorldId { - MainWorld = 0, - ApplicationWorld, - UserWorld - }; - Q_ENUM(ScriptWorldId) - - QQuickWebEngineScript(); - ~QQuickWebEngineScript(); - Q_INVOKABLE QString toString() const; - - QString name() const; - QUrl sourceUrl() const; - QString sourceCode() const; - InjectionPoint injectionPoint() const; - ScriptWorldId worldId() const; - bool runOnSubframes() const; + Q_DECLARE_PUBLIC(QQuickWebEngineScript) + QQuickWebEngineScriptPrivate(); + void aboutToUpdateUnderlyingScript(); + void bind(QtWebEngineCore::UserResourceControllerHost *, QtWebEngineCore::WebContentsAdapter * = 0); -public Q_SLOTS: - void setName(QString arg); - void setSourceUrl(QUrl arg); - void setSourceCode(QString arg); - void setInjectionPoint(InjectionPoint arg); - void setWorldId(ScriptWorldId arg); - void setRunOnSubframes(bool arg); - -Q_SIGNALS: - void nameChanged(QString arg); - void sourceUrlChanged(QUrl arg); - void sourceCodeChanged(QString arg); - void injectionPointChanged(InjectionPoint arg); - void worldIdChanged(ScriptWorldId arg); - void runOnSubframesChanged(bool arg); - -protected: - void timerEvent(QTimerEvent *e) override; + QtWebEngineCore::UserScript coreScript; + QBasicTimer m_basicTimer; + QtWebEngineCore::UserResourceControllerHost *m_controllerHost; + QtWebEngineCore::WebContentsAdapter *m_adapter; + QUrl m_sourceUrl; private: - friend class QQuickWebEngineViewPrivate; - Q_DECLARE_PRIVATE(QQuickWebEngineScript) - QScopedPointer<QQuickWebEngineScriptPrivate> d_ptr; + QQuickWebEngineScript *q_ptr; + }; + QT_END_NAMESPACE #endif // QQUICKWEBENGINESCRIPT_P_H diff --git a/src/webengine/api/qquickwebenginescript_p_p.h b/src/webengine/api/qquickwebenginescript_p_p.h deleted file mode 100644 index 4525505c6..000000000 --- a/src/webengine/api/qquickwebenginescript_p_p.h +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** -** -** 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$ -** -****************************************************************************/ - -#ifndef QQUICKWEBENGINESCRIPT_P_P_H -#define QQUICKWEBENGINESCRIPT_P_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qquickwebenginescript_p.h" - -#include <QtCore/QBasicTimer> -#include "user_script.h" -#include "web_contents_adapter.h" - -namespace QtWebEngineCore { -class UserResourceControllerHost; -class WebContentsAdapter; -} // namespace - -QT_BEGIN_NAMESPACE - -class QQuickWebEngineScriptPrivate { -public: - Q_DECLARE_PUBLIC(QQuickWebEngineScript) - QQuickWebEngineScriptPrivate(); - void aboutToUpdateUnderlyingScript(); - void bind(QtWebEngineCore::UserResourceControllerHost *, QtWebEngineCore::WebContentsAdapter * = 0); - - QtWebEngineCore::UserScript coreScript; - QBasicTimer m_basicTimer; - QtWebEngineCore::UserResourceControllerHost *m_controllerHost; - QtWebEngineCore::WebContentsAdapter *m_adapter; - QUrl m_sourceUrl; - -private: - QQuickWebEngineScript *q_ptr; - -}; - -QT_END_NAMESPACE - -#endif // QQUICKWEBENGINESCRIPT_P_P_H diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp index a19f0be53..2db25584c 100644 --- a/src/webengine/api/qquickwebengineview.cpp +++ b/src/webengine/api/qquickwebengineview.cpp @@ -55,7 +55,7 @@ #include "qquickwebenginenewviewrequest_p.h" #include "qquickwebengineprofile_p.h" #include "qquickwebenginesettings_p.h" -#include "qquickwebenginescript_p_p.h" +#include "qquickwebenginescript_p.h" #ifdef ENABLE_QML_TESTSUPPORT_API #include "qquickwebenginetestsupport_p.h" @@ -1527,8 +1527,13 @@ void QQuickWebEngineView::dragLeaveEvent(QDragLeaveEvent *e) void QQuickWebEngineView::dragMoveEvent(QDragMoveEvent *e) { Q_D(QQuickWebEngineView); - e->accept(); - d->adapter->updateDragPosition(e, mapToScreen(this, e->pos())); + Qt::DropAction dropAction = d->adapter->updateDragPosition(e, mapToScreen(this, e->pos())); + if (Qt::IgnoreAction == dropAction) { + e->ignore(); + } else { + e->setDropAction(dropAction); + e->accept(); + } } void QQuickWebEngineView::dropEvent(QDropEvent *e) diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h index 27224fadd..92eb5d7de 100644 --- a/src/webengine/api/qquickwebengineview_p.h +++ b/src/webengine/api/qquickwebengineview_p.h @@ -52,7 +52,7 @@ // #include <private/qtwebengineglobal_p.h> -#include "qquickwebenginescript_p.h" +#include "qquickwebenginescript.h" #include <QQuickItem> #include <QtGui/qcolor.h> diff --git a/src/webengine/doc/src/qtwebengine-overview.qdoc b/src/webengine/doc/src/qtwebengine-overview.qdoc index c3d737384..ff35b45cf 100644 --- a/src/webengine/doc/src/qtwebengine-overview.qdoc +++ b/src/webengine/doc/src/qtwebengine-overview.qdoc @@ -197,11 +197,16 @@ \section1 Proxy Support - Qt WebEngine uses the proxy settings from \l{Qt Network}. If - QNetworkProxy::applicationProxy is set, it will also be used for Qt WebEngine, and if - QNetworkProxyFactory::usesSystemConfiguration() is enabled, the proxy settings are automatically - retrieved from the system. Settings from an installed QNetworkProxyFactory will be ignored - though. + Qt WebEngine uses the proxy settings from \l{Qt Network}, and forwards them to Chromium's + networking stack. If QNetworkProxy::applicationProxy is set, it will also be used for Qt + WebEngine. If QNetworkProxyFactory::usesSystemConfiguration() is enabled, the proxy settings + are automatically retrieved from the system. Settings from an installed QNetworkProxyFactory + will be ignored, though. + + Not all properties of QNetworkProxy are supported by Qt WebEngine. That is, + QNetworkProxy::type(), QNetworkProxy::hostName() and QNetworkProxy::port() are taken into + account. All other proxy settings such as QNetworkProxy::rawHeader(), QNetworkProxy::user(), or + QNetworkProxy::password() are ignored. If a proxy requires authentication, QWebEnginePage::proxyAuthenticationRequired is emitted. For Qt Quick, a dialog is shown. diff --git a/src/webengine/render_widget_host_view_qt_delegate_quick.h b/src/webengine/render_widget_host_view_qt_delegate_quick.h index 385a98a3c..7a08e915b 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quick.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quick.h @@ -74,6 +74,7 @@ public: virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint&) Q_DECL_OVERRIDE { } virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; + virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE { } // The QtQuick view doesn't have a backbuffer of its own and doesn't need this virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h index d0a5e480c..057b91c75 100644 --- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h +++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.h @@ -77,6 +77,7 @@ public: virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; virtual void inputMethodStateChanged(bool) Q_DECL_OVERRIDE {} + virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE { } virtual void setClearColor(const QColor &) Q_DECL_OVERRIDE { } private: diff --git a/src/webengine/webengine.pro b/src/webengine/webengine.pro index 5fa49c77e..27239225b 100644 --- a/src/webengine/webengine.pro +++ b/src/webengine/webengine.pro @@ -45,6 +45,7 @@ HEADERS = \ api/qquickwebenginenewviewrequest_p.h \ api/qquickwebengineprofile.h \ api/qquickwebengineprofile_p.h \ + api/qquickwebenginescript.h \ api/qquickwebenginescript_p.h \ api/qquickwebenginesettings_p.h \ api/qquickwebenginesingleton_p.h \ diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp index 27268d26b..69ecbe160 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.cpp @@ -323,6 +323,11 @@ void RenderWidgetHostViewQtDelegateWidget::inputMethodStateChanged(bool editorVi qApp->inputMethod()->setVisible(editorVisible); } +void RenderWidgetHostViewQtDelegateWidget::setInputMethodHints(Qt::InputMethodHints hints) +{ + QQuickWidget::setInputMethodHints(hints); +} + void RenderWidgetHostViewQtDelegateWidget::setClearColor(const QColor &color) { QQuickWidget::setClearColor(color); diff --git a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h index 68e6a176b..fb33c55c7 100644 --- a/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h +++ b/src/webenginewidgets/render_widget_host_view_qt_delegate_widget.h @@ -75,6 +75,7 @@ public: virtual void resize(int width, int height) Q_DECL_OVERRIDE; virtual void move(const QPoint &screenPos) Q_DECL_OVERRIDE; virtual void inputMethodStateChanged(bool editorVisible) Q_DECL_OVERRIDE; + virtual void setInputMethodHints(Qt::InputMethodHints) Q_DECL_OVERRIDE; virtual void setClearColor(const QColor &color) Q_DECL_OVERRIDE; protected: diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp index f9fd854cc..5cc0d18df 100644 --- a/tests/auto/quick/publicapi/tst_publicapi.cpp +++ b/tests/auto/quick/publicapi/tst_publicapi.cpp @@ -34,6 +34,7 @@ #include <QQmlListProperty> #include <QtTest/QtTest> #include <QtWebEngine/QQuickWebEngineProfile> +#include <QtWebEngine/QQuickWebEngineScript> #include <private/qquickwebengineview_p.h> #include <private/qquickwebenginecertificateerror_p.h> #include <private/qquickwebenginedialogrequests_p.h> @@ -42,7 +43,6 @@ #include <private/qquickwebengineloadrequest_p.h> #include <private/qquickwebenginenavigationrequest_p.h> #include <private/qquickwebenginenewviewrequest_p.h> -#include <private/qquickwebenginescript_p.h> #include <private/qquickwebenginesettings_p.h> #include <private/qquickwebenginesingleton_p.h> #include <private/qquickwebenginecontextmenurequest_p.h> diff --git a/tests/auto/quick/qmltests/data/tst_userScripts.qml b/tests/auto/quick/qmltests/data/tst_userScripts.qml index 88fa6f6e3..e9a4eba99 100644 --- a/tests/auto/quick/qmltests/data/tst_userScripts.qml +++ b/tests/auto/quick/qmltests/data/tst_userScripts.qml @@ -61,6 +61,12 @@ Item { } TestWebEngineView { + id: webEngineView2 + width: 400 + height: 300 + } + + TestWebEngineView { id: webEngineViewWithConditionalUserScripts width: 400 height: 300 @@ -82,6 +88,7 @@ Item { function init() { webEngineView.url = ""; webEngineView.userScripts = []; + webEngineView.profile.userScripts = []; } function test_oneScript() { @@ -173,5 +180,17 @@ Item { webEngineView.waitForLoadSucceeded(); tryCompare(webEngineView, "title", "Test page with huge link area"); } + + function test_profileWideScript() { + webEngineView.profile.userScripts = [ changeDocumentTitleScript ]; + + webEngineView.url = Qt.resolvedUrl("test1.html"); + webEngineView.waitForLoadSucceeded(); + compare(webEngineView.title, "New title"); + + webEngineView2.url = Qt.resolvedUrl("test1.html"); + webEngineView2.waitForLoadSucceeded(); + compare(webEngineView2.title, "New title"); + } } } diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp index 2ae699310..8df84e048 100644 --- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp +++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp @@ -34,6 +34,7 @@ #include <QtGui/qpa/qwindowsysteminterface.h> #include <QtQml/QQmlEngine> #include <QtTest/QtTest> +#include <QtWebEngine/QQuickWebEngineProfile> #include <private/qquickwebengineview_p.h> #include <functional> @@ -77,6 +78,7 @@ private Q_SLOTS: void inputEventForwardingDisabledWhenActiveFocusOnPressDisabled(); void changeLocale(); + void userScripts(); private: inline QQuickWebEngineView *newWebEngineView(); @@ -720,5 +722,28 @@ void tst_QQuickWebEngineView::changeLocale() delete viewEN; } +void tst_QQuickWebEngineView::userScripts() +{ + QScopedPointer<QQuickWebEngineView> webEngineView1(newWebEngineView()); + webEngineView1->setParentItem(m_window->contentItem()); + QScopedPointer<QQuickWebEngineView> webEngineView2(newWebEngineView()); + webEngineView2->setParentItem(m_window->contentItem()); + + QQmlListReference list(webEngineView1->profile(), "userScripts"); + QQuickWebEngineScript script; + script.setSourceCode("document.title = 'New title';"); + list.append(&script); + + webEngineView1->setUrl(urlFromTestPath("html/basic_page.html")); + QVERIFY(waitForLoadSucceeded(webEngineView1.data())); + QTRY_COMPARE(webEngineView1->title(), QStringLiteral("New title")); + + webEngineView2->setUrl(urlFromTestPath("html/basic_page.html")); + QVERIFY(waitForLoadSucceeded(webEngineView2.data())); + QTRY_COMPARE(webEngineView2->title(), QStringLiteral("New title")); + + list.clear(); +} + QTEST_MAIN(tst_QQuickWebEngineView) #include "tst_qquickwebengineview.moc" diff --git a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro index fef92c311..e0765736e 100644 --- a/tests/auto/widgets/qwebenginepage/qwebenginepage.pro +++ b/tests/auto/widgets/qwebenginepage/qwebenginepage.pro @@ -1,4 +1,4 @@ include(../tests.pri) -QT *= core-private gui-private +QT *= core-private contains(WEBENGINE_CONFIG, use_pdf): DEFINES+=QWEBENGINEPAGE_PDFPRINTINGENABLED diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp index 5467ce39e..7e78e2b0e 100644 --- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp +++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp @@ -32,17 +32,15 @@ #include <QOpenGLWidget> #include <QPaintEngine> #include <QPushButton> +#include <QScreen> #include <QStateMachine> -#include <QStyle> #include <QtGui/QClipboard> #include <QtTest/QtTest> #include <QTextCharFormat> #include <QWebChannel> -#include <private/qinputmethod_p.h> #include <qnetworkcookiejar.h> #include <qnetworkreply.h> #include <qnetworkrequest.h> -#include <qpa/qplatforminputcontext.h> #include <qwebenginedownloaditem.h> #include <qwebenginefullscreenrequest.h> #include <qwebenginehistory.h> @@ -66,38 +64,6 @@ static void removeRecursive(const QString& dirname) QDir().rmdir(dirname); } -class TestInputContext : public QPlatformInputContext -{ -public: - TestInputContext() - : m_visible(false) - { - QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = this; - } - - ~TestInputContext() - { - QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); - inputMethodPrivate->testContext = 0; - } - - virtual void showInputPanel() - { - m_visible = true; - } - virtual void hideInputPanel() - { - m_visible = false; - } - virtual bool isInputPanelVisible() const - { - return m_visible; - } - - bool m_visible; -}; - class tst_QWebEnginePage : public QObject { Q_OBJECT @@ -1671,24 +1637,6 @@ void tst_QWebEnginePage::inputMethods_data() } #if defined(QWEBENGINEPAGE_INPUTMETHODQUERY) -static Qt::InputMethodHints inputMethodHints(QObject* object) -{ - if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object)) - return o->inputMethodHints(); - if (QWidget* w = qobject_cast<QWidget*>(object)) - return w->inputMethodHints(); - return Qt::InputMethodHints(); -} - -static bool inputMethodEnabled(QObject* object) -{ - if (QGraphicsObject* o = qobject_cast<QGraphicsObject*>(object)) - return o->flags() & QGraphicsItem::ItemAcceptsInputMethod; - if (QWidget* w = qobject_cast<QWidget*>(object)) - return w->testAttribute(Qt::WA_InputMethodEnabled); - return false; -} - static void clickOnPage(QWebEnginePage* page, const QPoint& position) { QMouseEvent evpres(QEvent::MouseButtonPress, position, Qt::LeftButton, Qt::NoButton, Qt::NoModifier); @@ -1741,32 +1689,6 @@ void tst_QWebEnginePage::inputMethods() clickOnPage(page, textInputCenter); - // This part of the test checks if the SIP (Software Input Panel) is triggered, - // which normally happens on mobile platforms, when a user input form receives - // a mouse click. - int inputPanel = 0; - if (viewType == "QWebEngineView") { - if (QWebEngineView* wv = qobject_cast<QWebEngineView*>(view)) - inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); - } else if (viewType == "QGraphicsWebView") { - if (QGraphicsWebView* wv = qobject_cast<QGraphicsWebView*>(view)) - inputPanel = wv->style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); - } - - // For non-mobile platforms RequestSoftwareInputPanel event is not called - // because there is no SIP (Software Input Panel) triggered. In the case of a - // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked - // and the RequestSoftwareInputPanel event is called. For these two situations - // this part of the test can verified as the checks below. - if (inputPanel) - QVERIFY(testContext.isInputPanelVisible()); - else - QVERIFY(!testContext.isInputPanelVisible()); - testContext.hideInputPanel(); - - clickOnPage(page, textInputCenter); - QVERIFY(testContext.isInputPanelVisible()); - //ImMicroFocus QVariant variant = page->inputMethodQuery(Qt::ImMicroFocus); QVERIFY(inputs.at(0).geometry().contains(variant.toRect().topLeft())); @@ -1960,38 +1882,6 @@ void tst_QWebEnginePage::inputMethods() //END - Tests for Selection when the Editor is not in Composition mode - //ImhHiddenText - QPoint passwordInputCenter = inputs.at(1).geometry().center(); - clickOnPage(page, passwordInputCenter); - - QVERIFY(inputMethodEnabled(view)); - QVERIFY(inputMethodHints(view) & Qt::ImhHiddenText); - - clickOnPage(page, textInputCenter); - QVERIFY(!(inputMethodHints(view) & Qt::ImhHiddenText)); - - page->setHtml("<html><body><p>nothing to input here"); - testContext.hideInputPanel(); - - QWebEngineElement para = page->mainFrame()->findFirstElement("p"); - clickOnPage(page, para.geometry().center()); - - QVERIFY(!testContext.isInputPanelVisible()); - - //START - Test for sending empty QInputMethodEvent - page->setHtml("<html><body>" \ - "<input type='text' id='input3' value='QtWebEngine2'/>" \ - "</body></html>"); - evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input3'); inputEle.focus(); inputEle.select();"); - - //Send empty QInputMethodEvent - QInputMethodEvent emptyEvent; - page->event(&emptyEvent); - - QString inputValue = evaluateJavaScriptSync(page, "document.getElementById('input3').value").toString(); - QCOMPARE(inputValue, QString("QtWebEngine2")); - //END - Test for sending empty QInputMethodEvent - page->setHtml("<html><body>" \ "<input type='text' id='input4' value='QtWebEngine inputMethod'/>" \ "</body></html>"); @@ -2299,98 +2189,6 @@ void tst_QWebEnginePage::inputMethods() variant = page->inputMethodQuery(Qt::ImAnchorPosition); anchorPosition = variant.toInt(); QCOMPARE(anchorPosition, 12); - - // Check sending RequestSoftwareInputPanel event - page->setHtml("<html><body>" \ - "<input type='text' id='input5' value='QtWebEngine inputMethod'/>" \ - "<div id='btnDiv' onclick='i=document.getElementById("input5"); i.focus();'>abc</div>"\ - "</body></html>"); - QWebEngineElement inputElement = page->mainFrame()->findFirstElement("div"); - clickOnPage(page, inputElement.geometry().center()); - - QVERIFY(!testContext.isInputPanelVisible()); - - // START - Newline test for textarea - qApp->processEvents(); - page->setHtml("<html><body>" \ - "<textarea rows='5' cols='1' id='input5' value=''/>" \ - "</body></html>"); - evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input5'); inputEle.focus(); inputEle.select();"); - - // Enter Key without key text - QKeyEvent keyEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); - page->event(&keyEnter); - QList<QInputMethodEvent::Attribute> attribs; - - QInputMethodEvent eventText(QString(), attribs); - eventText.setCommitString("\n"); - page->event(&eventText); - - QInputMethodEvent eventText2(QString(), attribs); - eventText2.setCommitString("third line"); - page->event(&eventText2); - qApp->processEvents(); - - QString inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Enter Key with key text '\r' - evaluateJavaScriptSync(page, "var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyEnterWithCarriageReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\r"); - page->event(&keyEnterWithCarriageReturn); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Enter Key with key text '\n' - page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyEnterWithLineFeed(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n"); - page->event(&keyEnterWithLineFeed); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Enter Key with key text "\n\r" - page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyEnterWithLFCR(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n\r"); - page->event(&keyEnterWithLFCR); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // Return Key without key text - page->runJavaScript("var inputEle = document.getElementById('input5'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("")); - - QKeyEvent keyReturn(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); - page->event(&keyReturn); - page->event(&eventText); - page->event(&eventText2); - qApp->processEvents(); - - inputValue2 = evaluateJavaScriptSync(page, "document.getElementById('input5').value").toString(); - QCOMPARE(inputValue2, QString("\n\nthird line")); - - // END - Newline test for textarea #endif } diff --git a/tests/auto/widgets/qwebengineview/qwebengineview.pro b/tests/auto/widgets/qwebengineview/qwebengineview.pro index e99c7f493..d91c0074b 100644 --- a/tests/auto/widgets/qwebengineview/qwebengineview.pro +++ b/tests/auto/widgets/qwebengineview/qwebengineview.pro @@ -1 +1,2 @@ include(../tests.pri) +QT *= gui-private diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp index 53c7650fb..b173c3474 100644 --- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp +++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp @@ -22,8 +22,10 @@ #include <qtest.h> #include "../util.h" +#include <private/qinputmethod_p.h> #include <qpainter.h> #include <qpagelayout.h> +#include <qpa/qplatforminputcontext.h> #include <qwebengineview.h> #include <qwebenginepage.h> #include <qwebenginesettings.h> @@ -39,6 +41,7 @@ #include <QtWebEngineCore/qwebenginehttprequest.h> #include <QTcpServer> #include <QTcpSocket> +#include <QStyle> #define VERIFY_INPUTMETHOD_HINTS(actual, expect) \ QVERIFY(actual == expect); @@ -91,6 +94,11 @@ private Q_SLOTS: void keyboardEvents(); void keyboardFocusAfterPopup(); void postData(); + + void softwareInputPanel(); + void hiddenText(); + void emptyInputMethodEvent(); + void newlineInTextarea(); }; // This will be called before the first test function is executed. @@ -1216,5 +1224,264 @@ void tst_QWebEngineView::postData() server.close(); } +class TestInputContext : public QPlatformInputContext +{ +public: + TestInputContext() + : m_visible(false) + { + QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = this; + } + + ~TestInputContext() + { + QInputMethodPrivate* inputMethodPrivate = QInputMethodPrivate::get(qApp->inputMethod()); + inputMethodPrivate->testContext = 0; + } + + virtual void showInputPanel() + { + m_visible = true; + } + virtual void hideInputPanel() + { + m_visible = false; + } + virtual bool isInputPanelVisible() const + { + return m_visible; + } + + bool m_visible; +}; + +static QPoint elementCenter(QWebEnginePage *page, const QString &id) +{ + const QString jsCode( + "(function(){" + " var elem = document.getElementById('" + id + "');" + " var rect = elem.getBoundingClientRect();" + " return [(rect.left + rect.right) / 2, (rect.top + rect.bottom) / 2];" + "})()"); + QVariantList rectList = evaluateJavaScriptSync(page, jsCode).toList(); + + if (rectList.count() != 2) { + qWarning("elementCenter failed."); + return QPoint(); + } + + return QPoint(rectList.at(0).toInt(), rectList.at(1).toInt()); +} + +void tst_QWebEngineView::softwareInputPanel() +{ + TestInputContext testContext; + QWebEngineView view; + view.show(); + + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " <input type='text' id='input1' value='' size='50'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + QPoint textInputCenter = elementCenter(view.page(), "input1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + + // This part of the test checks if the SIP (Software Input Panel) is triggered, + // which normally happens on mobile platforms, when a user input form receives + // a mouse click. + int inputPanel = view.style()->styleHint(QStyle::SH_RequestSoftwareInputPanel); + + // For non-mobile platforms RequestSoftwareInputPanel event is not called + // because there is no SIP (Software Input Panel) triggered. In the case of a + // mobile platform, an input panel, e.g. virtual keyboard, is usually invoked + // and the RequestSoftwareInputPanel event is called. For these two situations + // this part of the test can verified as the checks below. + if (inputPanel) + QTRY_VERIFY(testContext.isInputPanelVisible()); + else + QTRY_VERIFY(!testContext.isInputPanelVisible()); + testContext.hideInputPanel(); + + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_VERIFY(testContext.isInputPanelVisible()); + + view.setHtml("<html><body><p id='para'>nothing to input here</p></body></html>"); + QVERIFY(loadFinishedSpy.wait()); + testContext.hideInputPanel(); + + QPoint paraCenter = elementCenter(view.page(), "para"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, paraCenter); + + QVERIFY(!testContext.isInputPanelVisible()); + + // Check sending RequestSoftwareInputPanel event + view.page()->setHtml("<html><body>" + " <input type='text' id='input1' value='QtWebEngine inputMethod'/>" + " <div id='btnDiv' onclick='i=document.getElementById("input1"); i.focus();'>abc</div>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + QPoint btnDivCenter = elementCenter(view.page(), "btnDiv"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, btnDivCenter); + + QVERIFY(!testContext.isInputPanelVisible()); +} + +void tst_QWebEngineView::hiddenText() +{ + QWebEngineView view; + view.show(); + + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " <input type='text' id='input1' value='QtWebEngine' size='50'/><br>" + " <input type='password' id='password1'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + QPoint passwordInputCenter = elementCenter(view.page(), "password1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, passwordInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("password1")); + + QVERIFY(view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled)); + QVERIFY(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText); + + QPoint textInputCenter = elementCenter(view.page(), "input1"); + QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1")); + QVERIFY(!(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText)); +} + +void tst_QWebEngineView::emptyInputMethodEvent() +{ + QWebEngineView view; + view.show(); + + QSignalSpy selectionChangedSpy(&view, SIGNAL(selectionChanged())); + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.setHtml("<html><body>" + " <input type='text' id='input1' value='QtWebEngine'/>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(!evaluateJavaScriptSync(view.page(), "window.getSelection().toString()").toString().isEmpty()); + + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QVERIFY(selectionChangedSpy.wait(100)); + QEXPECT_FAIL("", "https://bugreports.qt.io/browse/QTBUG-53134", Continue); + QCOMPARE(selectionChangedSpy.count(), 1); + + // Send empty QInputMethodEvent + QInputMethodEvent emptyEvent; + QApplication::sendEvent(view.focusProxy(), &emptyEvent); + + QString inputValue = evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(); + QCOMPARE(inputValue, QString("QtWebEngine")); +} + +void tst_QWebEngineView::newlineInTextarea() +{ + QWebEngineView view; + view.show(); + + QSignalSpy loadFinishedSpy(&view, SIGNAL(loadFinished(bool))); + view.page()->setHtml("<html><body>" + " <textarea rows='5' cols='1' id='input1'></textarea>" + "</body></html>"); + QVERIFY(loadFinishedSpy.wait()); + + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + // Enter Key without key text + QKeyEvent keyPressEnter(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); + QKeyEvent keyReleaseEnter(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::sendEvent(view.focusProxy(), &keyPressEnter); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnter); + + QList<QInputMethodEvent::Attribute> attribs; + + QInputMethodEvent eventText(QString(), attribs); + eventText.setCommitString("\n"); + QApplication::sendEvent(view.focusProxy(), &eventText); + + QInputMethodEvent eventText2(QString(), attribs); + eventText2.setCommitString("third line"); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Enter Key with key text '\r' + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressEnterWithCarriageReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\r"); + QKeyEvent keyReleaseEnterWithCarriageReturn(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::sendEvent(view.focusProxy(), &keyPressEnterWithCarriageReturn); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnterWithCarriageReturn); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Enter Key with key text '\n' + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressEnterWithLineFeed(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n"); + QKeyEvent keyReleaseEnterWithLineFeed(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier, "\n"); + QApplication::sendEvent(view.focusProxy(), &keyPressEnterWithLineFeed); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnterWithLineFeed); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Enter Key with key text "\n\r" + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressEnterWithLFCR(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier, "\n\r"); + QKeyEvent keyReleaseEnterWithLFCR(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier, "\n\r"); + QApplication::sendEvent(view.focusProxy(), &keyPressEnterWithLFCR); + QApplication::sendEvent(view.focusProxy(), &keyReleaseEnterWithLFCR); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); + + // Return Key without key text + evaluateJavaScriptSync(view.page(), "var inputEle = document.getElementById('input1'); inputEle.value = ''; inputEle.focus(); inputEle.select();"); + QTRY_VERIFY(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString().isEmpty()); + + QKeyEvent keyPressReturn(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier); + QKeyEvent keyReleaseReturn(QEvent::KeyRelease, Qt::Key_Enter, Qt::NoModifier); + QApplication::sendEvent(view.focusProxy(), &keyPressReturn); + QApplication::sendEvent(view.focusProxy(), &keyReleaseReturn); + + QApplication::sendEvent(view.focusProxy(), &eventText); + QApplication::sendEvent(view.focusProxy(), &eventText2); + + qApp->processEvents(); + QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.getElementById('input1').value").toString(), QString("\n\nthird line")); + QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImSurroundingText).toString(), QString("\n\nthird line")); +} + QTEST_MAIN(tst_QWebEngineView) #include "tst_qwebengineview.moc" diff --git a/tools/qmake/mkspecs/features/configure.prf b/tools/qmake/mkspecs/features/configure.prf index 759638877..48a1eb263 100644 --- a/tools/qmake/mkspecs/features/configure.prf +++ b/tools/qmake/mkspecs/features/configure.prf @@ -28,6 +28,12 @@ defineTest(runConfigure) { qtConfig(printing-and-pdf): WEBENGINE_CONFIG += use_printing use_pdf qtConfig(proprietary-codecs): WEBENGINE_CONFIG += use_proprietary_codecs qtConfig(spellchecker): WEBENGINE_CONFIG += use_spellchecker + qtConfig(webrtc): WEBENGINE_CONFIG += use_webrtc + qtConfig(embedded): WEBENGINE_CONFIG += embedded_build + } else { + cross_compile: WEBENGINE_CONFIG += embedded_build + } + isQtMinimum(5, 9) { qtConfig(appstore-compliant): WEBENGINE_CONFIG += use_appstore_compliant_code } @@ -36,14 +42,14 @@ defineTest(runConfigure) { !config_khr:skipBuild("khronos development headers appear to be missing (mesa/libegl1-mesa-dev)") REQUIRED_PACKAGES = dbus-1 fontconfig - !cross_compile: qtConfig(xcb): REQUIRED_PACKAGES += libdrm xcomposite xcursor xi xrandr xscrnsaver xtst + !contains(WEBENGINE_CONFIG, embedded_build): qtConfig(xcb): REQUIRED_PACKAGES += libdrm xcomposite xcursor xi xrandr xscrnsaver xtst qtConfig(pulseaudio): REQUIRED_PACKAGES += libpulse qtConfig(system-png): REQUIRED_PACKAGES += libpng qtConfig(system-harfbuzz) { packagesExist("\'harfbuzz >= 1.2.0\'"): WEBENGINE_CONFIG += use_system_harfbuzz else: log("System harfbuzz is too old (min. version 1.2). Using Chromium's copy.$${EOL}") } - !cross_compile: REQUIRED_PACKAGES += libpci + !contains(WEBENGINE_CONFIG, embedded_build): REQUIRED_PACKAGES += libpci for(package, $$list($$REQUIRED_PACKAGES)) { !packagesExist($$package):skipBuild("Unmet dependency: $$package") @@ -84,7 +90,7 @@ defineTest(runConfigure) { WEBENGINE_CONFIG += use_bundled_snappy } - !cross_compile { + !contains(WEBENGINE_CONFIG, embedded_build) { packagesExist(nss): WEBENGINE_CONFIG += use_nss else: log("System NSS not found, BoringSSL will be used.$${EOL}") } diff --git a/tools/qmake/mkspecs/features/functions.prf b/tools/qmake/mkspecs/features/functions.prf index a47e4b7e8..f3c2eb905 100644 --- a/tools/qmake/mkspecs/features/functions.prf +++ b/tools/qmake/mkspecs/features/functions.prf @@ -260,6 +260,11 @@ defineTest(isMinWinSDKVersion) { requested_minor = $$2 WIN_SDK_VERSION = $$(WindowsSDKVersion) + isEmpty(WIN_SDK_VERSION)|equals(WIN_SDK_VERSION, "\\") { + skipBuild("Could not detect Windows SDK version (\'WindowsSDKVersion\' environment variable is not set).") + return(false) + } + # major.0.minor major_version = $$section(WIN_SDK_VERSION, ., 0, 0) minor_version = $$section(WIN_SDK_VERSION, ., 2, 2) @@ -381,19 +386,23 @@ defineReplace(buildNinja) { !exists($$out) { mkpath($$dirname(out)) src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT") - ninja_configure = $$absolute_path(ninja/configure.py, $$src_3rd_party_dir) - system("cd $$system_quote($$system_path($$dirname(out))) && python $$system_quote($$system_path($$ninja_configure)) --bootstrap") + ninja_configure = $$system_quote($$system_path($$absolute_path(ninja/configure.py, $$src_3rd_party_dir))) + !system("cd $$system_quote($$system_path($$dirname(out))) && python $$ninja_configure --bootstrap") { + error("NINJA build error!") + } } } defineReplace(gnPath) { src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT") - out = $$shadowed($$absolute_path(chromium/tools/gn/gn, $$src_3rd_party_dir)) + out = $$shadowed($$absolute_path(chromium/tools/gn/out/Release/gn, $$src_3rd_party_dir)) + win32: out = $${out}.exe return($$out) } defineReplace(buildGn) { + gn_args = $$1 out = $$gnPath() !qtConfig(system-ninja): ninja_path = "--path $$ninjaPath()" # check if it is not already build @@ -401,9 +410,11 @@ defineReplace(buildGn) { mkpath($$dirname(out)) src_3rd_party_dir = $$absolute_path("$${getChromiumSrcDir()}/../", "$$QTWEBENGINE_ROOT") gn_bootstrap = $$system_path($$absolute_path(chromium/tools/gn/bootstrap/bootstrap.py, $$src_3rd_party_dir)) - gn_args = $$system_quote(is_clang=false use_sysroot=false enable_remoting=false enable_nacl=false) + gn_args = $$system_quote($$gn_args) gn_configure = $$system_quote($$gn_bootstrap) --shadow --gn-gen-args=$$gn_args $$ninja_path - system("cd $$system_quote($$system_path($$dirname(out))) && python $$gn_configure") + !system("cd $$system_quote($$system_path($$dirname(out))) && python $$gn_configure") { + error("GN build error!") + } } } diff --git a/tools/qmake/mkspecs/features/gn_generator.prf b/tools/qmake/mkspecs/features/gn_generator.prf index c5f283a99..ccc2831ae 100644 --- a/tools/qmake/mkspecs/features/gn_generator.prf +++ b/tools/qmake/mkspecs/features/gn_generator.prf @@ -10,6 +10,18 @@ defineReplace(getTargetType) { return("none") } +defineReplace(filter_flag_values) { + value_to_check = $$1 + macos:equals(value_to_check, "$(EXPORT_ARCH_ARGS)") { + # EXPORT_ARCH_ARGS comes from qtbase/mkspecs/features/mac/default_post.prf which is a way + # to figure out the architectures to pass to the compiler at Makefile time. Because this + # variable expansion is not supported by GN, we filter it out. GN takes care of assigning + # the architecture itself. + return("") + } + return($$value_to_check) +} + isEmpty(GN_FILE): GN_FILE = $$system_path($$_PRO_FILE_PWD_/BUILD.gn) isEmpty(GN_RUN_BINARY_SCRIPT): GN_RUN_BINARY_SCRIPT = "//build/gn_run_binary.py" isEmpty(GN_FIND_MOCABLES_SCRIPT): GN_FIND_MOCABLES_SCRIPT = "//build/gn_find_mocables.py" @@ -93,7 +105,7 @@ GN_CONTENTS += "}" TARGET_TYPE = $$getTargetType() GN_CONTENTS += "$${TARGET_TYPE}(\"$$TARGET\") {" - +!isEmpty(GN_CREATE_PRI): GN_CONTENTS += " create_pri_file = $$GN_CREATE_PRI" !isEmpty(GN_IMPORTS) { for (imp, GN_IMPORTS): GN_CONTENTS += " import(\"$$imp\")" } @@ -106,12 +118,19 @@ for (imp, GN_IMPORTS): GN_CONTENTS += " import(\"$$imp\")" !isEmpty(QMAKE_CFLAGS) { GN_CONTENTS += " cflags = [" - for(flag, QMAKE_CFLAGS): GN_CONTENTS += " \"$$flag\"," + for(flag, QMAKE_CFLAGS): GN_CONTENTS += " \"$$filter_flag_values($$flag)\"," GN_CONTENTS += " ]" } + +# Stop the barrage of unused variables warnings. +gcc|clang { + QMAKE_CXXFLAGS += "-Wno-unused-parameter" + QMAKE_CXXFLAGS += "-Wno-unused-variable" +} + !isEmpty(QMAKE_CXXFLAGS) { GN_CONTENTS += " cflags_cc = [" - for(flag, QMAKE_CXXFLAGS): GN_CONTENTS += " \"$$flag\"," + for(flag, QMAKE_CXXFLAGS): GN_CONTENTS += " \"$$filter_flag_values($$flag)\"," GN_CONTENTS += " ]" } @@ -119,7 +138,9 @@ GN_CONTENTS += " if (!defined(defines)) {"\ " defines = []"\ " }" GN_CONTENTS += " defines += [" -for (define, DEFINES): GN_CONTENTS += " \"$$define\"," +# Remove single quotes around function macro defines, so that GN doesn't escape them, thus breaking +# the macro. +for (define, DEFINES): GN_CONTENTS += " \"$$replace(define,\',)\"," !isEmpty(QMAKE_LIBDIR_EGL): GN_CONTENTS += " \"QT_LIBDIR_EGL=\\\"$${QMAKE_DIR_SEP}$$relative_path($$QMAKE_LIBDIR_EGL, $$[QT_SYSROOT])\\\"\"," !isEmpty(QMAKE_LIBDIR_OPENGL_ES2) @@ -147,9 +168,12 @@ GN_CONTENTS += " if (!defined(ldflags)) {"\ " ldflags = []"\ " }" GN_CONTENTS += " ldflags += [" -for (flag, QMAKE_LFLAGS): GN_CONTENTS += " \"$$flag\"," +for (flag, QMAKE_LFLAGS): GN_CONTENTS += " \"$$filter_flag_values($$flag)\"," for (flag, GN_FLAGS): GN_CONTENTS += " \"$$flag\"," -!isEmpty(QMAKE_RPATHDIR): GN_CONTENTS += " \"-Wl,-rpath=$${QMAKE_RPATHDIR}\"," +!isEmpty(QMAKE_RPATHDIR) { + macos: GN_CONTENTS += " \"-Wl,-rpath,$${QMAKE_RPATHDIR}\"," + else:unix: GN_CONTENTS += " \"-Wl,-rpath=$${QMAKE_RPATHDIR}\"," +} !isEmpty(QMAKE_RPATHLINKDIR): GN_CONTENTS += " \"-Wl,-rpath-link=$${QMAKE_RPATHLINKDIR}\"," GN_CONTENTS += " ]" |