summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
m---------src/3rdparty0
-rw-r--r--src/CMakeLists.txt46
-rw-r--r--src/core/CMakeLists.txt176
-rw-r--r--src/core/accessibility_activation_observer.cpp9
-rw-r--r--src/core/api/CMakeLists.txt91
-rw-r--r--src/core/api/Qt6WebEngineCoreDeploySupport.cmake173
-rw-r--r--src/core/api/Qt6WebEngineCoreMacros.cmake8
-rw-r--r--src/core/api/configure.cmake53
-rw-r--r--src/core/api/qtwebenginecoreglobal.cpp154
-rw-r--r--src/core/api/qtwebenginecoreglobal.h5
-rw-r--r--src/core/api/qtwebenginecoreglobal_p.h8
-rw-r--r--src/core/api/qwebengineclienthints.cpp211
-rw-r--r--src/core/api/qwebengineclienthints.h72
-rw-r--r--src/core/api/qwebenginecookiestore_p.h2
-rw-r--r--src/core/api/qwebenginedesktopmediarequest.cpp206
-rw-r--r--src/core/api/qwebenginedesktopmediarequest.h59
-rw-r--r--src/core/api/qwebenginedesktopmediarequest_p.h49
-rw-r--r--src/core/api/qwebenginedownloadrequest.cpp39
-rw-r--r--src/core/api/qwebenginedownloadrequest_p.h31
-rw-r--r--src/core/api/qwebenginefilesystemaccessrequest.cpp19
-rw-r--r--src/core/api/qwebengineglobalsettings.cpp125
-rw-r--r--src/core/api/qwebengineglobalsettings.h30
-rw-r--r--src/core/api/qwebengineglobalsettings_p.h44
-rw-r--r--src/core/api/qwebenginehistory.cpp7
-rw-r--r--src/core/api/qwebenginehistory_p.h2
-rw-r--r--src/core/api/qwebengineloadinginfo.cpp24
-rw-r--r--src/core/api/qwebengineloadinginfo.h8
-rw-r--r--src/core/api/qwebenginemessagepumpscheduler.cpp9
-rw-r--r--src/core/api/qwebenginemessagepumpscheduler_p.h5
-rw-r--r--src/core/api/qwebenginenavigationrequest.cpp3
-rw-r--r--src/core/api/qwebenginepage.cpp360
-rw-r--r--src/core/api/qwebenginepage.h17
-rw-r--r--src/core/api/qwebenginepage_p.h6
-rw-r--r--src/core/api/qwebengineprofile.cpp48
-rw-r--r--src/core/api/qwebengineprofile.h3
-rw-r--r--src/core/api/qwebengineprofile_p.h5
-rw-r--r--src/core/api/qwebenginescriptcollection_p.h2
-rw-r--r--src/core/api/qwebenginesettings.cpp15
-rw-r--r--src/core/api/qwebenginesettings.h13
-rw-r--r--src/core/api/qwebengineurlrequestinfo.cpp30
-rw-r--r--src/core/api/qwebengineurlrequestinfo.h5
-rw-r--r--src/core/api/qwebengineurlrequestinfo_p.h10
-rw-r--r--src/core/api/qwebengineurlrequestinterceptor.cpp11
-rw-r--r--src/core/api/qwebengineurlrequestinterceptor.h3
-rw-r--r--src/core/api/qwebengineurlrequestjob.cpp16
-rw-r--r--src/core/api/qwebengineurlrequestjob.h3
-rw-r--r--src/core/api/qwebengineurlscheme.cpp5
-rw-r--r--src/core/api/qwebengineurlscheme.h1
-rw-r--r--src/core/api/qwebengineurlschemehandler.cpp33
-rw-r--r--src/core/api/qwebenginewebauthuxrequest.cpp427
-rw-r--r--src/core/api/qwebenginewebauthuxrequest.h117
-rw-r--r--src/core/api/qwebenginewebauthuxrequest_p.h43
-rw-r--r--src/core/authentication_dialog_controller.h2
-rw-r--r--src/core/authenticator_request_client_delegate_qt.cpp247
-rw-r--r--src/core/authenticator_request_client_delegate_qt.h96
-rw-r--r--src/core/authenticator_request_dialog_controller.cpp302
-rw-r--r--src/core/authenticator_request_dialog_controller.h53
-rw-r--r--src/core/authenticator_request_dialog_controller_p.h78
-rw-r--r--src/core/autofill_client_qt.cpp47
-rw-r--r--src/core/autofill_client_qt.h28
-rw-r--r--src/core/autofill_popup_controller.cpp4
-rw-r--r--src/core/autofill_popup_controller.h2
-rw-r--r--src/core/browser_accessibility_manager_qt.cpp27
-rw-r--r--src/core/browser_accessibility_qt.cpp83
-rw-r--r--src/core/browser_accessibility_qt.h4
-rw-r--r--src/core/browser_main_parts_qt.cpp86
-rw-r--r--src/core/browser_message_filter_qt.h2
-rw-r--r--src/core/browsing_data_remover_delegate_qt.cpp7
-rw-r--r--src/core/browsing_data_remover_delegate_qt.h18
-rw-r--r--src/core/certificate_error_controller.h6
-rw-r--r--src/core/chromium_overrides.cpp15
-rw-r--r--src/core/client_cert_select_controller.cpp5
-rw-r--r--src/core/client_cert_select_controller.h2
-rw-r--r--src/core/client_hints.cpp12
-rw-r--r--src/core/client_hints.h2
-rw-r--r--src/core/clipboard_qt.cpp57
-rw-r--r--src/core/clipboard_qt.h23
-rw-r--r--src/core/color_chooser_controller.h2
-rw-r--r--src/core/compositor/compositor.cpp35
-rw-r--r--src/core/compositor/compositor.h56
-rw-r--r--src/core/compositor/content_gpu_client_qt.cpp9
-rw-r--r--src/core/compositor/content_gpu_client_qt.h10
-rw-r--r--src/core/compositor/display_overrides.cpp102
-rw-r--r--src/core/compositor/display_skia_output_device.cpp356
-rw-r--r--src/core/compositor/display_skia_output_device.h39
-rw-r--r--src/core/compositor/display_software_output_surface.cpp43
-rw-r--r--src/core/compositor/display_software_output_surface.h2
-rw-r--r--src/core/compositor/native_skia_output_device.cpp422
-rw-r--r--src/core/compositor/native_skia_output_device.h183
-rw-r--r--src/core/compositor/native_skia_output_device_direct3d11.cpp88
-rw-r--r--src/core/compositor/native_skia_output_device_direct3d11.h28
-rw-r--r--src/core/compositor/native_skia_output_device_mac.mm97
-rw-r--r--src/core/compositor/native_skia_output_device_metal.cpp66
-rw-r--r--src/core/compositor/native_skia_output_device_metal.h31
-rw-r--r--src/core/compositor/native_skia_output_device_opengl.cpp86
-rw-r--r--src/core/compositor/native_skia_output_device_opengl.h28
-rw-r--r--src/core/compositor/native_skia_output_device_vulkan.cpp306
-rw-r--r--src/core/compositor/native_skia_output_device_vulkan.h28
-rw-r--r--src/core/compositor/vulkan_implementation_qt.cpp77
-rw-r--r--src/core/compositor/vulkan_implementation_qt.h4
-rw-r--r--src/core/configure.json288
-rw-r--r--src/core/configure/BUILD.root.gn.in150
-rw-r--r--src/core/content_browser_client_qt.cpp104
-rw-r--r--src/core/content_browser_client_qt.h32
-rw-r--r--src/core/content_client_qt.cpp42
-rw-r--r--src/core/content_client_qt.h11
-rw-r--r--src/core/content_main_delegate_qt.cpp35
-rw-r--r--src/core/desktop_media_controller.cpp244
-rw-r--r--src/core/desktop_media_controller.h65
-rw-r--r--src/core/desktop_media_controller_p.h28
-rw-r--r--src/core/devtools_frontend_qt.cpp693
-rw-r--r--src/core/devtools_frontend_qt.h113
-rw-r--r--src/core/doc/about_credits_entry.tmpl3
-rw-r--r--src/core/doc/qtwebengine.qdocconf5
-rw-r--r--src/core/doc/snippets/qtwebengine_qwebenginepage_snippet.cpp6
-rw-r--r--src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc2
-rw-r--r--src/core/doc/src/qtwebengine-debugging.qdoc6
-rw-r--r--src/core/doc/src/qtwebengine-deploying.qdoc58
-rw-r--r--src/core/doc/src/qtwebengine-features.qdoc106
-rw-r--r--src/core/doc/src/qtwebengine-global.qdoc14
-rw-r--r--src/core/doc/src/qtwebengine-overview.qdoc5
-rw-r--r--src/core/doc/src/qtwebengine-platform-notes.qdoc45
-rw-r--r--src/core/doc/src/qwebengine-licensing.qdoc7
-rw-r--r--src/core/doc/src/qwebenginepage_lgpl.qdoc158
-rw-r--r--src/core/doc/src/qwebenginesettings_lgpl.qdoc63
-rw-r--r--src/core/download_manager_delegate_qt.cpp68
-rw-r--r--src/core/download_manager_delegate_qt.h2
-rw-r--r--src/core/extensions/extension_host_delegate_qt.cpp39
-rw-r--r--src/core/extensions/extension_host_delegate_qt.h2
-rw-r--r--src/core/extensions/extension_system_qt.cpp100
-rw-r--r--src/core/extensions/extension_system_qt.h18
-rw-r--r--src/core/extensions/extensions_api_client_qt.cpp16
-rw-r--r--src/core/extensions/extensions_api_client_qt.h5
-rw-r--r--src/core/extensions/extensions_browser_client_qt.cpp24
-rw-r--r--src/core/extensions/extensions_browser_client_qt.h12
-rw-r--r--src/core/extensions/file_system_delegate_qt.cpp146
-rw-r--r--src/core/extensions/file_system_delegate_qt.h89
-rw-r--r--src/core/extensions/pdf_iframe_navigation_throttle_qt.cpp27
-rw-r--r--src/core/favicon_service_factory_qt.cpp11
-rw-r--r--src/core/favicon_service_factory_qt.h4
-rw-r--r--src/core/file_picker_controller.cpp2
-rw-r--r--src/core/file_picker_controller.h2
-rw-r--r--src/core/file_system_access/file_system_access_permission_context_qt.cpp29
-rw-r--r--src/core/file_system_access/file_system_access_permission_context_qt.h5
-rw-r--r--src/core/file_system_access/file_system_access_permission_grant_qt.cpp6
-rw-r--r--src/core/file_system_access/file_system_access_permission_grant_qt.h3
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_controller.h2
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp2
-rw-r--r--src/core/file_system_access/file_system_access_permission_request_manager_qt.h2
-rw-r--r--src/core/find_text_helper.h2
-rw-r--r--src/core/javascript_dialog_controller.h2
-rw-r--r--src/core/javascript_dialog_controller_p.h2
-rw-r--r--src/core/location_provider_qt.cpp83
-rw-r--r--src/core/location_provider_qt.h11
-rw-r--r--src/core/login_delegate_qt.cpp13
-rw-r--r--src/core/macos_context_type_helper.h7
-rw-r--r--src/core/macos_context_type_helper.mm18
-rw-r--r--src/core/media_capture_devices_dispatcher.cpp120
-rw-r--r--src/core/media_capture_devices_dispatcher.h11
-rw-r--r--src/core/native_web_keyboard_event_qt.cpp58
-rw-r--r--src/core/native_web_keyboard_event_qt.h20
-rw-r--r--src/core/native_web_keyboard_event_qt_mac.mm155
-rw-r--r--src/core/net/client_cert_qt.cpp6
-rw-r--r--src/core/net/client_cert_qt.h4
-rw-r--r--src/core/net/client_cert_store_data.cpp3
-rw-r--r--src/core/net/cookie_monster_delegate_qt.cpp7
-rw-r--r--src/core/net/cookie_monster_delegate_qt.h2
-rw-r--r--src/core/net/custom_url_loader_factory.cpp15
-rw-r--r--src/core/net/plugin_response_interceptor_url_loader_throttle.cpp15
-rw-r--r--src/core/net/proxy_config_service_qt.cpp7
-rw-r--r--src/core/net/proxying_restricted_cookie_manager_qt.cpp38
-rw-r--r--src/core/net/proxying_restricted_cookie_manager_qt.h11
-rw-r--r--src/core/net/proxying_url_loader_factory_qt.cpp65
-rw-r--r--src/core/net/qrc_url_scheme_handler.cpp8
-rw-r--r--src/core/net/resource_request_body_qt.cpp181
-rw-r--r--src/core/net/resource_request_body_qt.h70
-rw-r--r--src/core/net/ssl_host_state_delegate_qt.cpp23
-rw-r--r--src/core/net/ssl_host_state_delegate_qt.h3
-rw-r--r--src/core/net/system_network_context_manager.cpp61
-rw-r--r--src/core/net/system_network_context_manager.h4
-rw-r--r--src/core/net/url_request_custom_job_delegate.cpp27
-rw-r--r--src/core/net/url_request_custom_job_delegate.h22
-rw-r--r--src/core/net/url_request_custom_job_proxy.cpp19
-rw-r--r--src/core/net/url_request_custom_job_proxy.h13
-rw-r--r--src/core/net/version_ui_qt.cpp56
-rw-r--r--src/core/net/version_ui_qt.h32
-rw-r--r--src/core/net/webui_controller_factory_qt.cpp13
-rw-r--r--src/core/ozone/gl_context_qt.cpp235
-rw-r--r--src/core/ozone/gl_context_qt.h47
-rw-r--r--src/core/ozone/gl_ozone_egl_qt.cpp76
-rw-r--r--src/core/ozone/gl_ozone_egl_qt.h13
-rw-r--r--src/core/ozone/gl_ozone_glx_qt.cpp15
-rw-r--r--src/core/ozone/gl_ozone_glx_qt.h6
-rw-r--r--src/core/ozone/gl_share_context_qt.cpp24
-rw-r--r--src/core/ozone/gl_share_context_qt.h2
-rw-r--r--src/core/ozone/gl_surface_egl_qt.cpp87
-rw-r--r--src/core/ozone/gl_surface_egl_qt.h3
-rw-r--r--src/core/ozone/gl_surface_glx_qt.cpp44
-rw-r--r--src/core/ozone/gl_surface_glx_qt.h2
-rw-r--r--src/core/ozone/gl_surface_qt.cpp75
-rw-r--r--src/core/ozone/gl_surface_qt.h3
-rw-r--r--src/core/ozone/gl_surface_wgl_qt.cpp4
-rw-r--r--src/core/ozone/gl_surface_wgl_qt.h2
-rw-r--r--src/core/ozone/ozone_extra.gni14
-rw-r--r--src/core/ozone/ozone_platform_qt.cpp65
-rw-r--r--src/core/ozone/platform_window_qt.cpp2
-rw-r--r--src/core/ozone/platform_window_qt.h2
-rw-r--r--src/core/ozone/surface_factory_qt.cpp211
-rw-r--r--src/core/ozone/surface_factory_qt.h22
-rw-r--r--src/core/pdf_util_qt.cpp92
-rw-r--r--src/core/pdf_util_qt.h34
-rw-r--r--src/core/permission_manager_qt.cpp138
-rw-r--r--src/core/permission_manager_qt.h30
-rw-r--r--src/core/pref_service_adapter.cpp21
-rw-r--r--src/core/printing/pdf_document_helper_client_qt.cpp33
-rw-r--r--src/core/printing/pdf_document_helper_client_qt.h27
-rw-r--r--src/core/printing/pdf_stream_delegate_qt.cpp40
-rw-r--r--src/core/printing/pdf_stream_delegate_qt.h4
-rw-r--r--src/core/printing/pdf_web_contents_helper_client_qt.cpp59
-rw-r--r--src/core/printing/pdf_web_contents_helper_client_qt.h27
-rw-r--r--src/core/printing/pdfium_document_wrapper_qt.h2
-rw-r--r--src/core/printing/print_view_manager_base_qt.cpp99
-rw-r--r--src/core/printing/print_view_manager_base_qt.h14
-rw-r--r--src/core/printing/print_view_manager_qt.cpp28
-rw-r--r--src/core/printing/printer_worker.cpp42
-rw-r--r--src/core/printing/printer_worker.h2
-rw-r--r--src/core/process_main.cpp1
-rw-r--r--src/core/profile_adapter.cpp126
-rw-r--r--src/core/profile_adapter.h27
-rw-r--r--src/core/profile_adapter_client.h4
-rw-r--r--src/core/profile_io_data_qt.cpp67
-rw-r--r--src/core/profile_io_data_qt.h28
-rw-r--r--src/core/profile_qt.cpp58
-rw-r--r--src/core/profile_qt.h19
-rw-r--r--src/core/render_view_context_menu_qt.h4
-rw-r--r--src/core/render_widget_host_view_qt.cpp36
-rw-r--r--src/core/render_widget_host_view_qt.h14
-rw-r--r--src/core/render_widget_host_view_qt_delegate.h2
-rw-r--r--src/core/render_widget_host_view_qt_delegate_client.cpp9
-rw-r--r--src/core/render_widget_host_view_qt_delegate_client.h2
-rw-r--r--src/core/render_widget_host_view_qt_delegate_item.cpp93
-rw-r--r--src/core/render_widget_host_view_qt_delegate_item.h6
-rw-r--r--src/core/renderer/content_renderer_client_qt.cpp34
-rw-r--r--src/core/renderer/extensions/resource_request_policy_qt.cpp9
-rw-r--r--src/core/renderer/plugins/loadable_plugin_placeholder_qt.h2
-rw-r--r--src/core/renderer/print_web_view_helper_delegate_qt.cpp30
-rw-r--r--src/core/renderer/user_resource_controller.cpp26
-rw-r--r--src/core/renderer/web_channel_ipc_transport.cpp17
-rw-r--r--src/core/renderer_host/user_resource_controller_host.h2
-rw-r--r--src/core/select_file_dialog_factory_qt.cpp2
-rw-r--r--src/core/tools/qwebengine_convert_dict/CMakeLists.txt (renamed from src/core/tools/CMakeLists.txt)10
-rw-r--r--src/core/tools/qwebengine_convert_dict/main.cpp (renamed from src/core/tools/main.cpp)2
-rw-r--r--src/core/tools/webenginedriver/CMakeLists.txt57
-rw-r--r--src/core/touch_handle_drawable_client.h2
-rw-r--r--src/core/touch_selection_controller_client_qt.h3
-rw-r--r--src/core/touch_selection_menu_controller.h2
-rw-r--r--src/core/type_conversion.cpp1
-rw-r--r--src/core/type_conversion.h10
-rw-r--r--src/core/visited_links_manager_qt.h2
-rw-r--r--src/core/web_contents_adapter.cpp114
-rw-r--r--src/core/web_contents_adapter.h4
-rw-r--r--src/core/web_contents_adapter_client.h6
-rw-r--r--src/core/web_contents_delegate_qt.cpp86
-rw-r--r--src/core/web_contents_delegate_qt.h13
-rw-r--r--src/core/web_contents_view_qt.h1
-rw-r--r--src/core/web_engine_context.cpp398
-rw-r--r--src/core/web_engine_context.h7
-rw-r--r--src/core/web_engine_context_threads.cpp102
-rw-r--r--src/core/web_engine_error.h2
-rw-r--r--src/core/web_engine_library_info.cpp21
-rw-r--r--src/core/web_engine_settings.cpp52
-rw-r--r--src/core/web_engine_settings.h4
-rw-r--r--src/core/web_event_factory.cpp57
-rw-r--r--src/core/web_event_factory.h2
-rw-r--r--src/gn/CMakeLists.txt25
-rw-r--r--src/host/BUILD.toolchain.gn.in1
-rw-r--r--src/host/CMakeLists.txt26
-rw-r--r--src/host/config.tests/hostcompiler/CMakeLists.txt11
-rw-r--r--src/host/config.tests/hostcompiler/main.cpp9
-rw-r--r--src/pdf/CMakeLists.txt67
-rw-r--r--src/pdf/configure/BUILD.root.gn.in21
-rw-r--r--src/pdf/doc/about_credits.tmpl1
-rw-r--r--src/pdf/doc/about_credits_entry.tmpl13
-rw-r--r--src/pdf/doc/images/pdfviewer.pngbin0 -> 264348 bytes
-rw-r--r--src/pdf/doc/images/singlepageviewer.webpbin0 -> 57680 bytes
-rw-r--r--src/pdf/doc/qtpdf.qdocconf2
-rw-r--r--src/pdf/doc/src/qtpdf-examples.qdoc1
-rw-r--r--src/pdf/doc/src/qtpdf-index.qdoc15
-rw-r--r--src/pdf/doc/src/qtpdf-licensing.qdoc18
-rw-r--r--src/pdf/doc/src/qtpdf-platformnotes.qdoc11
-rw-r--r--src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp10
-rw-r--r--src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h2
-rw-r--r--src/pdf/qpdfbookmarkmodel.cpp16
-rw-r--r--src/pdf/qpdfdocument.cpp161
-rw-r--r--src/pdf/qpdfdocument.h1
-rw-r--r--src/pdf/qpdfdocument_p.h37
-rw-r--r--src/pdf/qpdflinkmodel.cpp80
-rw-r--r--src/pdf/qpdflinkmodel.h67
-rw-r--r--src/pdf/qpdflinkmodel_p.h56
-rw-r--r--src/pdf/qpdflinkmodel_p_p.h44
-rw-r--r--src/pdf/qpdfpagenavigator.cpp8
-rw-r--r--src/pdf/qpdfsearchmodel.cpp34
-rw-r--r--src/pdf/qpdfsearchmodel.h4
-rw-r--r--src/pdf/qpdfsearchmodel_p.h2
-rw-r--r--src/pdf/qtpdfglobal.h19
-rw-r--r--src/pdfquick/+Material/PdfStyle.qml1
-rw-r--r--src/pdfquick/+Universal/PdfStyle.qml1
-rw-r--r--src/pdfquick/CMakeLists.txt1
-rw-r--r--src/pdfquick/PdfLinkDelegate.qml13
-rw-r--r--src/pdfquick/PdfMultiPageView.qml73
-rw-r--r--src/pdfquick/PdfPageView.qml4
-rw-r--r--src/pdfquick/PdfScrollablePageView.qml10
-rw-r--r--src/pdfquick/PdfStyle.qml2
-rw-r--r--src/pdfquick/doc/src/qtquickpdf-module.qdoc4
-rw-r--r--src/pdfquick/qquickpdfdocument.cpp21
-rw-r--r--src/pdfquick/qquickpdfpageimage.cpp14
-rw-r--r--src/pdfquick/qquickpdfsearchmodel.cpp9
-rw-r--r--src/pdfwidgets/CMakeLists.txt2
-rw-r--r--src/pdfwidgets/qpdfpageselector.cpp171
-rw-r--r--src/pdfwidgets/qpdfpageselector.h51
-rw-r--r--src/pdfwidgets/qpdfpageselector_p.h60
-rw-r--r--src/pdfwidgets/qpdfview.cpp215
-rw-r--r--src/pdfwidgets/qpdfview.h16
-rw-r--r--src/pdfwidgets/qpdfview_p.h10
-rw-r--r--src/process/CMakeLists.txt22
-rw-r--r--src/process/Info_mac.plist.in44
-rw-r--r--src/process/QtWebEngineProcess.entitlements2
-rw-r--r--src/webenginequick/CMakeLists.txt12
-rw-r--r--src/webenginequick/api/qquickwebengineaction.cpp10
-rw-r--r--src/webenginequick/api/qquickwebengineaction_p.h2
-rw-r--r--src/webenginequick/api/qquickwebengineclientcertificateselection_p.h4
-rw-r--r--src/webenginequick/api/qquickwebenginedialogrequests.cpp29
-rw-r--r--src/webenginequick/api/qquickwebenginedialogrequests_p.h10
-rw-r--r--src/webenginequick/api/qquickwebenginedownloadrequest_p.h2
-rw-r--r--src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h2
-rw-r--r--src/webenginequick/api/qquickwebengineforeigntypes_p.h55
-rw-r--r--src/webenginequick/api/qquickwebenginenewwindowrequest_p.h2
-rw-r--r--src/webenginequick/api/qquickwebengineprofile.cpp63
-rw-r--r--src/webenginequick/api/qquickwebengineprofile.h3
-rw-r--r--src/webenginequick/api/qquickwebengineprofile_p.h3
-rw-r--r--src/webenginequick/api/qquickwebenginescriptcollection_p.h2
-rw-r--r--src/webenginequick/api/qquickwebenginesettings.cpp112
-rw-r--r--src/webenginequick/api/qquickwebenginesettings_p.h26
-rw-r--r--src/webenginequick/api/qquickwebenginesingleton_p.h2
-rw-r--r--src/webenginequick/api/qquickwebenginetouchhandleprovider_p_p.h2
-rw-r--r--src/webenginequick/api/qquickwebengineview.cpp271
-rw-r--r--src/webenginequick/api/qquickwebengineview_p.h47
-rw-r--r--src/webenginequick/api/qquickwebengineview_p_p.h6
-rw-r--r--src/webenginequick/api/qtwebenginequickglobal.cpp14
-rw-r--r--src/webenginequick/api/qtwebenginequickglobal_p.h6
-rw-r--r--src/webenginequick/doc/snippets/minimal/main.cpp18
-rw-r--r--src/webenginequick/doc/snippets/minimal/main.qml18
-rw-r--r--src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc2
-rw-r--r--src/webenginequick/doc/snippets/qtwebengine_webengineaction.qml123
-rw-r--r--src/webenginequick/doc/src/qtwebengine-examples.qdoc1
-rw-r--r--src/webenginequick/doc/src/qtwebengine-qmlmodule.qdoc9
-rw-r--r--src/webenginequick/doc/src/webengine_certificate_error.qdoc4
-rw-r--r--src/webenginequick/doc/src/webengineview_lgpl.qdoc102
-rw-r--r--src/webenginequick/plugin.cpp4
-rw-r--r--src/webenginequick/qquickwebengine_accessible.cpp2
-rw-r--r--src/webenginequick/qquickwebengine_accessible_p.h (renamed from src/webenginequick/qquickwebengine_accessible.h)11
-rw-r--r--src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp2
-rw-r--r--src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h (renamed from src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h)11
-rw-r--r--src/webenginequick/ui/AlertDialog.qml1
-rw-r--r--src/webenginequick/ui/AuthenticationDialog.qml1
-rw-r--r--src/webenginequick/ui/CMakeLists.txt9
-rw-r--r--src/webenginequick/ui/ColorDialog.qml278
-rw-r--r--src/webenginequick/ui/ConfirmDialog.qml1
-rw-r--r--src/webenginequick/ui/PromptDialog.qml1
-rw-r--r--src/webenginequick/ui/custom/ColorDialog.qml285
-rw-r--r--src/webenginequick/ui_delegates_manager.cpp11
-rw-r--r--src/webenginequick/ui_delegates_manager_p.h (renamed from src/webenginequick/ui_delegates_manager.h)11
-rw-r--r--src/webenginewidgets/CMakeLists.txt3
-rw-r--r--src/webenginewidgets/api/qwebengineview.cpp128
-rw-r--r--src/webenginewidgets/api/qwebengineview_p.h4
-rw-r--r--src/webenginewidgets/doc/snippets/qtwebengine_qwebengineview_snippet.cpp2
-rw-r--r--src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc2
-rw-r--r--src/webenginewidgets/doc/snippets/simple/main.cpp11
-rw-r--r--src/webenginewidgets/doc/src/qtwebenginewidgets-examples.qdoc1
-rw-r--r--src/webenginewidgets/doc/src/qtwebenginewidgets-module.qdoc5
-rw-r--r--src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc10
-rw-r--r--src/webenginewidgets/plugins/qwebengineview/qwebengineview_plugin.cpp8
-rw-r--r--src/webenginewidgets/qwebengine_accessible.cpp2
-rw-r--r--src/webenginewidgets/qwebengine_accessible_p.h (renamed from src/webenginewidgets/qwebengine_accessible.h)11
384 files changed, 12043 insertions, 4717 deletions
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 1ccfe20ad92be86adf8e6bbb8b71b64dc1f9531
+Subproject 814db44bc99f79d0c4a847e0cac4a398034ee2f
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 771446ece..0084697f2 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -5,8 +5,10 @@
# MAIN CONFIGURE
##
-get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." REALPATH)
-get_filename_component(WEBENGINE_ROOT_BUILD_DIR "${PROJECT_BINARY_DIR}" REALPATH)
+qt_internal_get_filename_path_mode(path_mode)
+
+get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/.." ${path_mode})
+get_filename_component(WEBENGINE_ROOT_BUILD_DIR "${PROJECT_BINARY_DIR}" ${path_mode})
# Note this is configure that does not belong to any module
qt_feature_module_begin(ONLY_EVALUATE_FEATURES)
@@ -76,13 +78,13 @@ if(QT_FEATURE_qtpdf_build)
add_subdirectory(pdf)
# keep log order, pdf build after webengine
if(QT_FEATURE_qtwebengine_core_build)
- add_dependencies(run_pdf_GnReady WebEngineCore)
+ add_dependencies(run_pdf_NinjaReady WebEngineCore)
endif()
if(QT_FEATURE_qtwebengine_widgets_build)
- add_dependencies(run_pdf_GnReady WebEngineWidgets)
+ add_dependencies(run_pdf_NinjaReady WebEngineWidgets)
endif()
if(QT_FEATURE_qtwebengine_quick_build)
- add_dependencies(run_pdf_GnReady WebEngineQuick)
+ add_dependencies(run_pdf_NinjaReady WebEngineQuick)
endif()
if(QT_FEATURE_qtpdf_widgets_build)
add_subdirectory(pdfwidgets)
@@ -140,6 +142,7 @@ if(NOT Gn_FOUND)
-DCMAKE_INSTALL_PREFIX:PATH=<INSTALL_DIR>
-DCMAKE_PREFIX_PATH:PATH=<INSTALL_DIR>
-DWEBENGINE_ROOT_BUILD_DIR=${PROJECT_BINARY_DIR}
+ -DQT_ALLOW_SYMLINK_IN_PATHS=${QT_ALLOW_SYMLINK_IN_PATHS}
)
if(QT_FEATURE_qtwebengine_core_build)
add_dependencies(run_core_GnReady gn)
@@ -149,7 +152,8 @@ if(NOT Gn_FOUND)
endif()
endif()
-if(NOT Gn_FOUND OR Gn_EXECUTABLE MATCHES "^${installDir}")
+string(REGEX REPLACE "(.)" "\\\\\\1" path_to_match "${installDir}")
+if(NOT Gn_FOUND OR Gn_EXECUTABLE MATCHES "^${path_to_match}")
set(INSTALL_GN 1 CACHE INTERNAL "")
endif()
@@ -169,7 +173,8 @@ if(CMAKE_CROSSCOMPILING AND NOT IOS AND NOT MACOS)
PREFIX host
USES_TERMINAL_BUILD TRUE
EXCLUDE_FROM_ALL TRUE
- CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${QT_HOST_PATH}/lib/cmake/Qt6/qt.toolchain.cmake
+ CMAKE_ARGS -DCMAKE_TOOLCHAIN_FILE=${QT_HOST_PATH_CMAKE_DIR}/Qt6/qt.toolchain.cmake
+ -DQT_USE_ORIGINAL_COMPILER=ON
-DWEBENGINE_ROOT_BUILD_DIR=${PROJECT_BINARY_DIR}
-DWEBENGINE_ROOT_SOURCE_DIR=${WEBENGINE_ROOT_SOURCE_DIR}
-DGN_TARGET_CPU=${TEST_architecture_arch}
@@ -187,29 +192,32 @@ if(CMAKE_CROSSCOMPILING AND NOT IOS AND NOT MACOS)
endif()
# install gn for cross build
-if((LINUX OR MACOS) AND INSTALL_GN)
- get_install_config(installConfig)
- install(
- PROGRAMS ${installDir}/bin/gn
- CONFIGURATIONS ${installConfig}
- RUNTIME DESTINATION "${INSTALL_LIBEXECDIR}"
- )
+if((LINUX OR MACOS OR WIN32) AND INSTALL_GN)
if(NOT QT_WILL_INSTALL)
- add_custom_target(copy-gn ALL DEPENDS
- ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/gn
+ set(copyOutput
+ ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/gn${CMAKE_EXECUTABLE_SUFFIX}
)
if(Gn_FOUND)
+ set(copyInput ${Gn_EXECUTABLE})
set(copyDep ${Gn_EXECUTABLE})
else()
+ set(copyInput ${installDir}/bin/gn${CMAKE_EXECUTABLE_SUFFIX})
set(copyDep gn)
endif()
+ add_custom_target(copy-gn ALL DEPENDS ${copyOutput})
add_custom_command(
- OUTPUT ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/gn
- COMMAND ${CMAKE_COMMAND} -E copy ${installDir}/bin/gn
- ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}
+ OUTPUT ${copyOutput}
+ COMMAND ${CMAKE_COMMAND} -E copy ${copyInput} ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}
DEPENDS ${copyDep}
USES_TERMINAL
)
+ else()
+ get_install_config(installConfig)
+ install(
+ PROGRAMS "${installDir}/bin/gn${CMAKE_EXECUTABLE_SUFFIX}"
+ CONFIGURATIONS ${installConfig}
+ RUNTIME DESTINATION "${INSTALL_LIBEXECDIR}"
+ )
endif()
endif()
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index fa8a7d18a..8ba77607b 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -4,7 +4,8 @@
cmake_minimum_required(VERSION 3.19)
find_package(Ninja 1.7.2 REQUIRED)
-find_package(Nodejs 12 REQUIRED)
+find_package(Nodejs 14.19 REQUIRED)
+find_package(Perl)
find_package(PkgConfig)
if(PkgConfig_FOUND)
create_pkg_config_host_wrapper(${CMAKE_CURRENT_BINARY_DIR})
@@ -13,7 +14,8 @@ endif()
set(buildDir "${CMAKE_CURRENT_BINARY_DIR}")
add_subdirectory(api)
-add_subdirectory(tools)
+add_subdirectory(tools/webenginedriver)
+add_subdirectory(tools/qwebengine_convert_dict)
##
# TOOLCHAIN SETUP
@@ -47,7 +49,7 @@ foreach(arch ${archs})
get_forward_declaration_macro(forwardDeclarationMacro)
get_target_property(qtWebEngineProcessName WebEngineCore QTWEBENGINEPROCESS_NAME)
- if(QT_FEATURE_debug_and_release AND ("${config}" STREQUAL "Debug"))
+ if("${config}" STREQUAL "Debug")
set(qtWebEngineProcessName "${qtWebEngineProcessName}${CMAKE_DEBUG_POSTFIX}")
endif()
@@ -69,14 +71,15 @@ foreach(arch ${archs})
DEFINES
QT_NO_KEYWORDS
QT_USE_QSTRINGBUILDER
- QTWEBENGINECORE_VERSION_STR=\\\\\\\\\"${QT_REPO_MODULE_VERSION}\\\\\\\\\"
- QTWEBENGINEPROCESS_NAME=\\\\\\\\\"${qtWebEngineProcessName}\\\\\\\\\"
+ QTWEBENGINECORE_VERSION_STR=${QT_REPO_MODULE_VERSION}
+ QTWEBENGINEPROCESS_NAME=${qtWebEngineProcessName}
BUILDING_CHROMIUM
"${forwardDeclarationMacro}"
CXX_COMPILE_OPTIONS
${gnCxxCompileOptions}
SOURCES
accessibility_tree_formatter_qt.cpp
+ browser_accessibility_qt.cpp browser_accessibility_qt.h
authentication_dialog_controller.cpp authentication_dialog_controller.h authentication_dialog_controller_p.h
autofill_client_qt.cpp autofill_client_qt.h
autofill_popup_controller.cpp autofill_popup_controller.h autofill_popup_controller_p.h
@@ -98,6 +101,7 @@ foreach(arch ${archs})
compositor/content_gpu_client_qt.cpp compositor/content_gpu_client_qt.h
compositor/display_overrides.cpp
compositor/display_software_output_surface.cpp compositor/display_software_output_surface.h
+ compositor/native_skia_output_device.cpp compositor/native_skia_output_device.h
content_browser_client_qt.cpp content_browser_client_qt.h
content_client_qt.cpp content_client_qt.h
content_main_delegate_qt.cpp content_main_delegate_qt.h
@@ -107,6 +111,7 @@ foreach(arch ${archs})
custom_handlers/register_protocol_handler_request_controller.h
custom_handlers/register_protocol_handler_request_controller_impl.cpp custom_handlers/register_protocol_handler_request_controller_impl.h
delegated_frame_host_client_qt.cpp delegated_frame_host_client_qt.h
+ desktop_media_controller.cpp desktop_media_controller.h desktop_media_controller_p.h
desktop_screen_qt.cpp desktop_screen_qt.h
devtools_frontend_qt.cpp devtools_frontend_qt.h
devtools_manager_delegate_qt.cpp devtools_manager_delegate_qt.h
@@ -126,7 +131,7 @@ foreach(arch ${archs})
javascript_dialog_manager_qt.cpp javascript_dialog_manager_qt.h
login_delegate_qt.cpp login_delegate_qt.h
media_capture_devices_dispatcher.cpp media_capture_devices_dispatcher.h
- native_web_keyboard_event_qt.cpp
+ native_web_keyboard_event_qt.cpp native_web_keyboard_event_qt.h
net/client_cert_qt.cpp net/client_cert_qt.h
net/client_cert_store_data.cpp net/client_cert_store_data.h
net/cookie_monster_delegate_qt.cpp net/cookie_monster_delegate_qt.h
@@ -136,10 +141,12 @@ foreach(arch ${archs})
net/proxying_restricted_cookie_manager_qt.cpp net/proxying_restricted_cookie_manager_qt.h
net/proxying_url_loader_factory_qt.cpp net/proxying_url_loader_factory_qt.h
net/qrc_url_scheme_handler.cpp net/qrc_url_scheme_handler.h
+ net/resource_request_body_qt.cpp net/resource_request_body_qt.h
net/ssl_host_state_delegate_qt.cpp net/ssl_host_state_delegate_qt.h
net/system_network_context_manager.cpp net/system_network_context_manager.h
net/url_request_custom_job_delegate.cpp net/url_request_custom_job_delegate.h
net/url_request_custom_job_proxy.cpp net/url_request_custom_job_proxy.h
+ net/version_ui_qt.cpp net/version_ui_qt.h
net/webui_controller_factory_qt.cpp net/webui_controller_factory_qt.h
ozone/gl_context_qt.cpp ozone/gl_context_qt.h
ozone/gl_ozone_egl_qt.cpp ozone/gl_ozone_egl_qt.h
@@ -150,6 +157,7 @@ foreach(arch ${archs})
ozone/platform_window_qt.cpp ozone/platform_window_qt.h
ozone/surface_factory_qt.cpp ozone/surface_factory_qt.h
permission_manager_qt.cpp permission_manager_qt.h
+ pdf_util_qt.cpp pdf_util_qt.h
platform_notification_service_qt.cpp platform_notification_service_qt.h
pointer_device_qt.cpp
pref_service_adapter.cpp pref_service_adapter.h
@@ -187,18 +195,18 @@ foreach(arch ${archs})
web_contents_delegate_qt.cpp web_contents_delegate_qt.h
web_contents_view_qt.cpp web_contents_view_qt.h
web_engine_context.cpp web_engine_context.h
- web_engine_context_threads.cpp
web_engine_error.cpp web_engine_error.h
web_engine_library_info.cpp web_engine_library_info.h
web_engine_settings.cpp web_engine_settings.h
web_event_factory.cpp web_event_factory.h
web_usb_detector_qt.cpp web_usb_detector_qt.h
+ authenticator_request_client_delegate_qt.cpp authenticator_request_client_delegate_qt.h
+ authenticator_request_dialog_controller.cpp authenticator_request_dialog_controller.h authenticator_request_dialog_controller_p.h
)
extend_gn_target(${buildGn} CONDITION QT_FEATURE_accessibility
SOURCES
accessibility_activation_observer.cpp accessibility_activation_observer.h
- browser_accessibility_qt.cpp browser_accessibility_qt.h
)
extend_gn_target(${buildGn} CONDITION QT_FEATURE_webengine_ozone_x11
@@ -209,6 +217,7 @@ foreach(arch ${archs})
extend_gn_target(${buildGn} CONDITION QT_FEATURE_webengine_vulkan
SOURCES
+ compositor/native_skia_output_device_vulkan.cpp compositor/native_skia_output_device_vulkan.h
compositor/vulkan_implementation_qt.cpp compositor/vulkan_implementation_qt.h
)
@@ -216,11 +225,14 @@ foreach(arch ${archs})
SOURCES
compositor/compositor_resource_fence.cpp compositor/compositor_resource_fence.h
compositor/display_skia_output_device.cpp compositor/display_skia_output_device.h
+ compositor/native_skia_output_device_opengl.cpp compositor/native_skia_output_device_opengl.h
)
- extend_gn_target(${buildGn} CONDITION MACOS AND QT_FEATURE_opengl
+ extend_gn_target(${buildGn} CONDITION MACOS
SOURCES
- macos_context_type_helper.mm macos_context_type_helper.h
+ native_web_keyboard_event_qt_mac.mm
+ compositor/native_skia_output_device_mac.mm
+ compositor/native_skia_output_device_metal.cpp compositor/native_skia_output_device_metal.h
)
extend_gn_target(${buildGn} CONDITION QT_FEATURE_webengine_pepper_plugins
@@ -260,6 +272,7 @@ foreach(arch ${archs})
extensions/extension_web_contents_observer_qt.cpp extensions/extension_web_contents_observer_qt.h
extensions/extensions_api_client_qt.cpp extensions/extensions_api_client_qt.h
extensions/extensions_browser_client_qt.cpp extensions/extensions_browser_client_qt.h
+ extensions/file_system_delegate_qt.cpp extensions/file_system_delegate_qt.h
extensions/messaging_delegate_qt.cpp extensions/messaging_delegate_qt.h
extensions/mime_handler_view_guest_delegate_qt.cpp extensions/mime_handler_view_guest_delegate_qt.h
extensions/plugin_service_filter_qt.cpp extensions/plugin_service_filter_qt.h
@@ -274,12 +287,13 @@ foreach(arch ${archs})
SOURCES
extensions/pdf_iframe_navigation_throttle_qt.cpp extensions/pdf_iframe_navigation_throttle_qt.h
printing/pdf_stream_delegate_qt.cpp printing/pdf_stream_delegate_qt.h
- printing/pdf_web_contents_helper_client_qt.cpp printing/pdf_web_contents_helper_client_qt.h
+ printing/pdf_document_helper_client_qt.cpp printing/pdf_document_helper_client_qt.h
)
extend_gn_target(${buildGn} CONDITION WIN32
SOURCES
clipboard_util_win.cpp
+ compositor/native_skia_output_device_direct3d11.cpp compositor/native_skia_output_device_direct3d11.h
)
##
@@ -296,11 +310,13 @@ foreach(arch ${archs})
list(APPEND gnArgArg
qtwebengine_target="${buildDir}/${config}/${arch}:QtWebEngineCore"
+ build_dawn_tests=false
build_with_tflite_lib=false
enable_background_contents=false
enable_background_mode=false
enable_ipc_fuzzer=false
- enable_js_type_check=false
+ enable_ipc_logging=false
+ enable_java_templates=false
enable_media_remoting=false
enable_message_center=false
enable_nacl=false
@@ -309,11 +325,12 @@ foreach(arch ${archs})
enable_reporting=false
enable_resource_allowlist_generation=false
enable_screen_ai_service=false
+ enable_session_service=false
+ enable_supervised_users=false
enable_swiftshader=false
enable_swiftshader_vulkan=false
angle_enable_swiftshader=false
dawn_use_swiftshader=false
- use_dawn=false
enable_vr=false
enable_web_speech=false
enable_widevine=true
@@ -321,19 +338,25 @@ foreach(arch ${archs})
fatal_linker_warnings=false
has_native_accessibility=false
safe_browsing_mode=0
- skia_use_dawn=false
toolkit_views=false
chrome_pgo_phase=0
optimize_webui=false
- v8_use_external_startup_data=false
strip_absolute_paths_from_debug_symbols=false
+ pdf_use_skia=true
+ use_dawn=false
+ skia_use_dawn=false
devtools_fast_bundle=false
devtools_skip_typecheck=false
- enable_jxl_decoder=false # temporarily because libjxl causes internal compiler error on armv7
+ use_static_angle=true
+ use_perfetto_client_library=false
+ trial_comparison_cert_verifier_supported=false
+ )
+ extend_gn_list(gnArgArg
+ ARGS use_v8_context_snapshot v8_use_external_startup_data
+ CONDITION QT_FEATURE_webengine_v8_context_snapshot
)
-
extend_gn_list(gnArgArg
- ARGS enable_basic_printing enable_print_preview enable_pdf
+ ARGS enable_printing enable_basic_printing enable_print_preview enable_pdf
CONDITION QT_FEATURE_webengine_printing_and_pdf
)
extend_gn_list(gnArgArg
@@ -342,9 +365,14 @@ foreach(arch ${archs})
)
extend_gn_list(gnArgArg
ARGS enable_plugins
- CONDITION QT_FEATURE_webengine_pepper_plugins
+ CONDITION QT_FEATURE_webengine_printing_and_pdf OR
+ QT_FEATURE_webengine_pepper_plugins
)
extend_gn_list(gnArgArg
+ ARGS enable_ppapi
+ CONDITION QT_FEATURE_webengine_pepper_plugins
+ )
+ extend_gn_list(gnArgArg
ARGS enable_spellcheck
CONDITION QT_FEATURE_webengine_spellchecker
)
@@ -353,6 +381,10 @@ foreach(arch ${archs})
CONDITION QT_FEATURE_webengine_webrtc
)
extend_gn_list(gnArgArg
+ ARGS enable_screen_capture
+ CONDITION QT_FEATURE_webengine_webrtc
+ )
+ extend_gn_list(gnArgArg
ARGS enable_hangout_services_extension
CONDITION QT_FEATURE_webengine_webrtc AND QT_FEATURE_webengine_extensions
)
@@ -365,6 +397,10 @@ foreach(arch ${archs})
CONDITION QT_FEATURE_webengine_extensions
)
extend_gn_list(gnArgArg
+ ARGS enable_vulkan
+ CONDITION QT_FEATURE_webengine_vulkan
+ )
+ extend_gn_list(gnArgArg
ARGS use_kerberos
CONDITION QT_FEATURE_webengine_kerberos
)
@@ -383,6 +419,10 @@ foreach(arch ${archs})
ARGS use_embedded_config
CONDITION QT_FEATURE_webengine_embedded_build
)
+ extend_gn_list(gnArgArg
+ ARGS enable_webenginedriver
+ CONDITION QT_FEATURE_webenginedriver
+ )
if(LINUX)
list(APPEND gnArgArg
@@ -390,13 +430,10 @@ foreach(arch ${archs})
use_qt=false # Qt5 toolkit bindings
use_cups=false
use_gio=false
- use_gnome_keyring=false
use_bundled_fontconfig=false
use_glib=false
use_bluez=false
- use_vaapi=false
use_udev=true
- enable_session_service=false
is_cfi=false
use_ozone=true
ozone_auto_platforms=false
@@ -406,7 +443,7 @@ foreach(arch ${archs})
ozone_extra_path="${CMAKE_CURRENT_LIST_DIR}/ozone/ozone_extra.gni"
)
set(systemLibs libjpeg libpng freetype harfbuzz libevent libwebp libxml
- opus snappy libvpx icu ffmpeg re2 lcms2
+ opus snappy icu ffmpeg re2 lcms2 libopenjpeg2 libvpx
)
foreach(slib ${systemLibs})
extend_gn_list(gnArgArg
@@ -414,6 +451,12 @@ foreach(arch ${archs})
CONDITION QT_FEATURE_webengine_system_${slib}
)
endforeach()
+ if(NOT QT_FEATURE_webengine_system_opus)
+ extend_gn_list(gnArgArg
+ ARGS has_perl
+ CONDITION Perl_FOUND
+ )
+ endif()
extend_gn_list(gnArgArg
ARGS use_system_libxslt
CONDITION QT_FEATURE_webengine_system_libxml
@@ -435,6 +478,10 @@ foreach(arch ${archs})
CONDITION QT_FEATURE_webengine_system_libpng
)
extend_gn_list(gnArgArg
+ ARGS pdfium_use_system_libtiff
+ CONDITION QT_FEATURE_webengine_system_libtiff
+ )
+ extend_gn_list(gnArgArg
ARGS use_libpci
CONDITION QT_FEATURE_webengine_system_libpci
)
@@ -447,6 +494,14 @@ foreach(arch ${archs})
CONDITION QT_FEATURE_webengine_system_pulseaudio
)
extend_gn_list(gnArgArg
+ ARGS use_system_minigbm
+ CONDITION QT_FEATURE_webengine_system_gbm
+ )
+ extend_gn_list(gnArgArg
+ ARGS use_vaapi
+ CONDITION QT_FEATURE_webengine_vaapi
+ )
+ extend_gn_list(gnArgArg
ARGS ozone_platform_x11 use_xkbcommon
CONDITION QT_FEATURE_webengine_ozone_x11
)
@@ -454,48 +509,48 @@ foreach(arch ${archs})
ARGS rtc_use_x11
CONDITION QT_FEATURE_webengine_ozone_x11 AND QT_FEATURE_webengine_webrtc
)
+ extend_gn_list(gnArgArg
+ ARGS use_vaapi_x11
+ CONDITION QT_FEATURE_webengine_ozone_x11 AND QT_FEATURE_webengine_vaapi
+ )
if(QT_FEATURE_webengine_kerberos)
list(APPEND gnArgArg
external_gssapi_include_dir="${GSSAPI_INCLUDE_DIRS}/gssapi"
)
endif()
-
+ get_gn_arch(cpu ${TEST_architecture_arch})
if(CMAKE_CROSSCOMPILING AND cpu STREQUAL "arm")
check_thumb(armThumb)
- if(NOT armThumb AND NOT QT_FEATURE_system_ffmpeg)
+ if(NOT armThumb AND NOT QT_FEATURE_webengine_system_ffmpeg)
list(APPEND gnArgArg media_use_ffmpeg=false use_webaudio_ffmpeg=false)
endif()
endif()
if(CMAKE_CROSSCOMPILING AND cpu STREQUAL "arm64")
- # V8 sandbox initialization is slow in QEMU.
# This is a workaround to avoid auto test timeouts on the QEMU arm64 CI.
if ("$ENV{TARGET_OSVERSION_COIN}" STREQUAL "qemu")
- list(APPEND gnArgArg v8_enable_sandbox=false)
+ list(APPEND gnArgArg
+ v8_enable_sandbox=false
+ arm_control_flow_integrity="none"
+ )
endif()
endif()
+ unset(cpu)
endif()
if(MACOS)
list(APPEND gnArgArg
use_external_popup_menu=false
- angle_enable_vulkan=false
+ skia_use_metal=false
)
endif()
- if(NOT CLANG)
- list(APPEND gnArgArg
- enable_location_source=false)
- endif()
-
if(WIN32)
list(APPEND gnArgArg
- enable_session_service=false
ninja_use_custom_environment_files=false
com_init_check_hook_disabled=true
heterogeneous_executables=true
- enable_vr=false
)
endif()
@@ -503,7 +558,7 @@ foreach(arch ${archs})
CMAKE_TARGET WebEngineCore
NINJA_TARGETS QtWebEngineCore convert_dict
GN_TARGET ${buildGn}
- GN_ARGS "${gnArgArg}"
+ GN_ARGS ${gnArgArg}
BUILDDIR ${buildDir}/${config}/${arch}
MODULE core
)
@@ -524,7 +579,20 @@ target_include_directories(WebEngineCore PRIVATE
${buildDir}/$<CONFIG>/${arch}/gen/third_party/perfetto/build_config
)
-add_gn_build_aritfacts_to_target(WebEngineCore QtWebEngineCore core ${buildDir} FALSE)
+set(stamps QtWebEngineCore.stamp)
+if(QT_FEATURE_webengine_v8_context_snapshot)
+ set(dataStamp obj/tools/v8_context_snapshot/v8_context_snapshot.stamp)
+endif()
+
+add_gn_build_artifacts_to_target(
+ CMAKE_TARGET WebEngineCore
+ NINJA_TARGET QtWebEngineCore
+ MODULE core
+ BUILDDIR ${buildDir}
+ COMPLETE_STATIC FALSE
+ NINJA_STAMP QtWebEngineCore.stamp
+ NINJA_DATA_STAMP ${dataStamp}
+)
add_dependencies(WebEngineCore run_core_NinjaDone)
if(COIN_BUG_699)
set_property(TARGET WebEngineCore PROPERTY CXX_LINKER_LAUNCHER ${PROJECT_BINARY_DIR}/linker_ulimit.sh)
@@ -566,8 +634,40 @@ if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING)
../3rdparty/chromium/third_party/boringssl/src/include
${buildDir}/$<CONFIG>/${arch}/gen
)
- add_gn_build_aritfacts_to_target(${dict_target_name} convert_dict core ${buildDir} FALSE)
+ add_gn_build_artifacts_to_target(
+ CMAKE_TARGET ${dict_target_name}
+ NINJA_TARGET convert_dict
+ MODULE core
+ BUILDDIR ${buildDir}
+ COMPLETE_STATIC FALSE
+ NINJA_STAMP convert_dict.stamp
+ )
add_dependencies(${dict_target_name} run_core_NinjaDone)
add_dependencies(${dict_target_name} WebEngineCore)
endif()
+##
+# WEBENGINEDRIVER
+##
+
+if(QT_FEATURE_webenginedriver)
+ add_ninja_command(
+ TARGET webenginedriver_group
+ OUTPUT ${WEBENGINEDRIVER_EXECUTABLE}
+ BUILDDIR ${buildDir}/$<CONFIG>/${arch}
+ MODULE core
+ )
+ add_custom_target(webenginedriver
+ DEPENDS
+ ${buildDir}/$<CONFIG>/${arch}/${WEBENGINEDRIVER_EXECUTABLE})
+ add_dependencies(run_core_NinjaDone webenginedriver)
+endif()
+
+##
+# CHROMIUM UPDATE
+##
+
+add_custom_target(update-chromium
+ COMMAND ${CMAKE_COMMAND} -P ${WEBENGINE_ROOT_SOURCE_DIR}/cmake/SubmoduleUpdate.cmake
+ DEPENDS ${WEBENGINE_ROOT_SOURCE_DIR}/cmake/SubmoduleUpdate.cmake
+)
diff --git a/src/core/accessibility_activation_observer.cpp b/src/core/accessibility_activation_observer.cpp
index 179a780d0..4f25a35ff 100644
--- a/src/core/accessibility_activation_observer.cpp
+++ b/src/core/accessibility_activation_observer.cpp
@@ -10,12 +10,13 @@ namespace QtWebEngineCore {
namespace {
bool isAccessibilityEnabled() {
- // On Linux accessibility is disabled by default due to performance issues,
- // and can be re-enabled by setting the QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment
- // variable. For details, see QTBUG-59922.
+ // On Linux accessibility can be disabled due to performance issues by setting the
+ // QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment variable to 0. For details,
+ // see QTBUG-59922.
#ifdef Q_OS_LINUX
static bool accessibility_enabled
- = qEnvironmentVariableIsSet("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY");
+ = qEnvironmentVariable("QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY", QLatin1String("1"))
+ == QLatin1String("1");
#else
const bool accessibility_enabled = true;
#endif
diff --git a/src/core/api/CMakeLists.txt b/src/core/api/CMakeLists.txt
index 0ee286031..f2ceb2dfd 100644
--- a/src/core/api/CMakeLists.txt
+++ b/src/core/api/CMakeLists.txt
@@ -12,8 +12,10 @@ qt_internal_add_module(WebEngineCore
qwebenginecertificateerror.cpp qwebenginecertificateerror.h
qwebengineclientcertificateselection.cpp qwebengineclientcertificateselection.h
qwebengineclientcertificatestore.cpp qwebengineclientcertificatestore.h
+ qwebengineclienthints.cpp qwebengineclienthints.h
qwebenginecontextmenurequest.cpp qwebenginecontextmenurequest.h qwebenginecontextmenurequest_p.h
qwebenginecookiestore.cpp qwebenginecookiestore.h qwebenginecookiestore_p.h
+ qwebenginedesktopmediarequest.cpp qwebenginedesktopmediarequest.h qwebenginedesktopmediarequest_p.h
qwebenginedownloadrequest.cpp qwebenginedownloadrequest.h qwebenginedownloadrequest_p.h
qwebenginefilesystemaccessrequest.cpp qwebenginefilesystemaccessrequest.h
qwebenginefindtextresult.cpp qwebenginefindtextresult.h
@@ -33,18 +35,20 @@ qt_internal_add_module(WebEngineCore
qwebenginescriptcollection.cpp qwebenginescriptcollection.h qwebenginescriptcollection_p.h
qwebenginesettings.cpp qwebenginesettings.h
qwebengineurlrequestinfo.cpp qwebengineurlrequestinfo.h qwebengineurlrequestinfo_p.h
- qwebengineurlrequestinterceptor.h
+ qwebengineurlrequestinterceptor.h qwebengineurlrequestinterceptor.cpp
qwebengineurlrequestjob.cpp qwebengineurlrequestjob.h
qwebengineurlscheme.cpp qwebengineurlscheme.h
qwebengineurlschemehandler.cpp qwebengineurlschemehandler.h
+ qwebengineglobalsettings.cpp qwebengineglobalsettings.h qwebengineglobalsettings_p.h
+ qwebenginewebauthuxrequest.cpp qwebenginewebauthuxrequest.h qwebenginewebauthuxrequest_p.h
DEFINES
BUILDING_CHROMIUM
- NOMINMAX
INCLUDE_DIRECTORIES
../
../../3rdparty/chromium
../../3rdparty/chromium/third_party/abseil-cpp
../../3rdparty/chromium/third_party/perfetto/include
+ ../../3rdparty/chromium/third_party/boringssl/src/include
LIBRARIES
Qt::CorePrivate
Qt::GuiPrivate
@@ -54,15 +58,28 @@ qt_internal_add_module(WebEngineCore
Qt::Gui
Qt::Network
Qt::Quick
+ EXTRA_CMAKE_FILES
+ "${CMAKE_CURRENT_LIST_DIR}/${INSTALL_CMAKE_NAMESPACE}WebEngineCoreDeploySupport.cmake"
+ NO_GENERATE_CPP_EXPORTS
)
set_target_properties(WebEngineCore PROPERTIES QTWEBENGINEPROCESS_NAME ${qtWebEngineProcessName})
+set_target_properties(WebEngineCore PROPERTIES CXX_STANDARD 20)
# Chromium included headers are not clean
qt_skip_warnings_are_errors(WebEngineCore)
if(CLANG OR GCC)
- target_compile_options(WebEngineCore PRIVATE "-Wno-unused-parameter")
+ target_compile_options(WebEngineCore PRIVATE
+ "-Wno-unused-parameter"
+ "-Wno-expansion-to-defined"
+ )
+endif()
+
+if(GCC)
+ target_compile_options(WebEngineCore PRIVATE
+ "-Wno-packed-not-aligned"
+ )
endif()
qt_internal_extend_target(WebEngineCore CONDITION QT_FEATURE_webengine_webchannel
@@ -74,6 +91,11 @@ qt_internal_extend_target(WebEngineCore CONDITION QT_FEATURE_webengine_geolocati
Qt::Positioning
)
+get_install_config(config)
+get_architectures(archs)
+get_configs(configs)
+list(GET archs 0 arch)
+
##
# DOCS
##
@@ -82,18 +104,16 @@ qt_internal_add_docs(WebEngineCore
../doc/qtwebengine.qdocconf
)
-add_custom_command(
- OUTPUT chromium_attributions.qdoc
- COMMAND ${Python3_EXECUTABLE} chromium/tools/licenses.py
- --file-template ../core/doc/about_credits.tmpl
- --entry-template ../core/doc/about_credits_entry.tmpl
- credits ${CMAKE_CURRENT_BINARY_DIR}/chromium_attributions.qdoc
- DEPENDS ../doc/about_credits.tmpl ../doc/about_credits_entry.tmpl
- WORKING_DIRECTORY ${WEBENGINE_ROOT_SOURCE_DIR}/src/3rdparty
- USES_TERMINAL
+add_code_attributions_target(
+ TARGET generate_chromium_attributions
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/chromium_attributions.qdoc
+ GN_TARGET :QtWebEngineCore
+ FILE_TEMPLATE ../doc/about_credits.tmpl
+ ENTRY_TEMPLATE ../doc/about_credits_entry.tmpl
+ BUILDDIR ${buildDir}/${config}/${arch}
)
-add_custom_target(generate_chromium_attributions DEPENDS chromium_attributions.qdoc)
-add_dependencies(generate_docs_WebEngineCore generate_chromium_attributions)
+add_dependencies(generate_chromium_attributions run_core_GnDone)
+add_dependencies(prepare_docs_WebEngineCore generate_chromium_attributions)
##
# WEBENGINECORE RESOURCES
@@ -109,22 +129,49 @@ set(resourceList qtwebengine_resources.pak
qtwebengine_resources_200p.pak
qtwebengine_devtools_resources.pak)
-get_install_config(config)
-get_architectures(archs)
-list(GET archs 0 arch)
+set(stamps ${buildDir}/${config}/${arch}/QtWebEngineCore.stamp)
+
+qt_internal_get_filename_path_mode(path_mode)
+
+if(QT_FEATURE_webengine_v8_context_snapshot)
+ foreach(arch ${archs})
+ foreach(config ${configs})
+ if(MACOS)
+ set(ext_arch ".${arch}")
+ # QTBUG-118120 gn does not support x86_64h
+ if(ext_arch STREQUAL "x86_64h")
+ set(ext_arch "x86_64")
+ endif()
+ else()
+ unset(ext_arch)
+ endif()
+ if("${config}" STREQUAL "Debug")
+ set(ext_debug ".debug")
+ else()
+ unset(ext_debug)
+ endif()
+ get_filename_component(resSourcePath ${buildDir}/${config}/${arch}/v8_context_snapshot${ext_arch}${ext_debug}.bin ${path_mode})
+ list(APPEND resourceFiles ${resSourcePath})
+ if(MACOS)
+ set(stamps ${stamps} ${buildDir}/${config}/${arch}/obj/tools/v8_context_snapshot/v8_context_snapshot.stamp)
+ endif()
+ endforeach()
+ endforeach()
+endif()
foreach(loc ${localeList})
- get_filename_component(locSourcePath ${buildDir}/${config}/${arch}/qtwebengine_locales/${loc}.pak REALPATH)
+ get_filename_component(locSourcePath ${buildDir}/${config}/${arch}/qtwebengine_locales/${loc}.pak ${path_mode})
list(APPEND localeFiles ${locSourcePath})
endforeach()
foreach(res ${resourceList})
- get_filename_component(resSourcePath ${buildDir}/${config}/${arch}/${res} REALPATH)
+ get_filename_component(resSourcePath ${buildDir}/${config}/${arch}/${res} ${path_mode})
list(APPEND resourceFiles ${resSourcePath})
endforeach()
-if (NOT QT_FEATURE_webengine_system_icu)
- get_filename_component(icuFile ${buildDir}/${config}/${arch}/icudtl.dat REALPATH)
+
+if(NOT QT_FEATURE_webengine_system_icu)
+ get_filename_component(icuFile ${buildDir}/${config}/${arch}/icudtl.dat ${path_mode})
list(APPEND resourceFiles ${icuFile})
set_target_properties(WebEngineCore PROPERTIES ICUDTL_FILE ${icuFile})
endif()
@@ -144,7 +191,7 @@ if(QT_FEATURE_framework)
GENERATED TRUE
)
- add_custom_command(OUTPUT ${allResourceFiles} DEPENDS ${buildDir}/${config}/${arch}/QtWebEngineCore.stamp)
+ add_custom_command(OUTPUT ${allResourceFiles} DEPENDS "${stamps}")
add_custom_target(generate_resources_${config} DEPENDS ${allResourceFiles})
addCopyCommand(WebEngineCore "${localeFiles}"
diff --git a/src/core/api/Qt6WebEngineCoreDeploySupport.cmake b/src/core/api/Qt6WebEngineCoreDeploySupport.cmake
new file mode 100644
index 000000000..e67eb212b
--- /dev/null
+++ b/src/core/api/Qt6WebEngineCoreDeploySupport.cmake
@@ -0,0 +1,173 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+# NOTE: This code should only ever be executed in script mode. It expects to be
+# used either as part of an install(CODE) call or called by a script
+# invoked via cmake -P as a POST_BUILD step. It would not normally be
+# included directly, it should be pulled in automatically by the deploy
+# support set up by qtbase.
+
+cmake_minimum_required(VERSION 3.16...3.21)
+
+_qt_internal_add_deployment_hook(_qt_internal_webenginecore_deploy_hook)
+
+if(NOT QT_DEPLOY_WEBENGINECORE_RESOURCES_DIR)
+ set(QT_DEPLOY_WEBENGINECORE_RESOURCES_DIR "resources")
+endif()
+
+function(_qt_internal_webenginecore_status_message)
+ if(__QT_DEPLOY_VERBOSE)
+ message(STATUS ${ARGV})
+ endif()
+endfunction()
+
+function(_qt_internal_webenginecore_deploy_hook)
+ set(no_value_options "")
+ set(single_value_options "")
+ set(multi_value_options RESOLVED_DEPENDENCIES)
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ set(webenginecore_dependency_found FALSE)
+ foreach(dependency IN LISTS arg_RESOLVED_DEPENDENCIES)
+ if(dependency MATCHES "/libQt[0-9]+WebEngineCore[^/]+")
+ set(webenginecore_dependency_found TRUE)
+ break()
+ endif()
+ endforeach()
+
+ if(NOT webenginecore_dependency_found)
+ _qt_internal_webenginecore_status_message(
+ "No QtWebEngineCore dependency found. "
+ "Skipping deployment of QtWebEngine assets."
+ )
+ return()
+ endif()
+
+ _qt_internal_deploy_webenginecore()
+endfunction()
+
+function(_qt_internal_deploy_webenginecore)
+ _qt_internal_deploy_webenginecore_binary()
+ _qt_internal_deploy_webenginecore_data()
+ _qt_internal_deploy_webenginecore_translations()
+endfunction()
+
+function(_qt_internal_deploy_webenginecore_binary)
+ _qt_internal_webenginecore_status_message("Deploying the WebEngineCore process binary")
+
+ set(candidates "QtWebEngineProcess")
+ if(__QT_DEPLOY_ACTIVE_CONFIG STREQUAL "Debug" AND __QT_DEPLOY_SYSTEM_NAME STREQUAL "Windows")
+ list(PREPEND candidates "QtWebEngineProcessd")
+ endif()
+
+ list(TRANSFORM candidates
+ PREPEND "${__QT_DEPLOY_QT_INSTALL_PREFIX}/${__QT_DEPLOY_QT_INSTALL_LIBEXECS}/"
+ )
+
+ set(process_path "")
+ foreach(file_path IN LISTS candidates)
+ if(EXISTS "${file_path}")
+ set(process_path "${file_path}")
+ break()
+ endif()
+ endforeach()
+
+ set(install_destination "${QT_DEPLOY_PREFIX}/")
+ if(__QT_DEPLOY_SYSTEM_NAME STREQUAL "Windows")
+ string(APPEND install_destination "${QT_DEPLOY_BIN_DIR}")
+ else()
+ string(APPEND install_destination "${QT_DEPLOY_LIBEXEC_DIR}")
+ endif()
+ file(INSTALL "${process_path}" DESTINATION "${install_destination}")
+
+ get_filename_component(process_file_name "${process_path}" NAME)
+ if(CMAKE_VERSION GREATER_EQUAL "3.19")
+ file(CHMOD "${install_destination}/${process_file_name}"
+ PERMISSIONS OWNER_EXECUTE OWNER_READ OWNER_WRITE
+ GROUP_EXECUTE GROUP_READ
+ WORLD_EXECUTE WORLD_READ
+ )
+ else()
+ execute_process(
+ COMMAND chmod 0755 "${install_destination}/${process_file_name}"
+ )
+ endif()
+endfunction()
+
+function(_qt_internal_deploy_webenginecore_data)
+ _qt_internal_webenginecore_status_message("Deploying the WebEngineCore data files")
+ set(data_files
+ icudtl.dat
+ qtwebengine_devtools_resources.pak
+ qtwebengine_resources.pak
+ qtwebengine_resources_100p.pak
+ qtwebengine_resources_200p.pak
+ )
+ get_filename_component(resources_dir "resources" ABSOLUTE
+ BASE_DIR "${__QT_DEPLOY_QT_INSTALL_PREFIX}/${__QT_DEPLOY_QT_INSTALL_DATA}"
+ )
+
+ _qt_internal_webenginecore_find_v8_context_snapshot(
+ snapshot_file
+ RESOURCES_DIR "${resources_dir}"
+ )
+ if(NOT snapshot_file STREQUAL "")
+ list(APPEND data_files "${snapshot_file}")
+ endif()
+
+ get_filename_component(install_destination "${QT_DEPLOY_WEBENGINECORE_RESOURCES_DIR}" ABSOLUTE
+ BASE_DIR "${QT_DEPLOY_PREFIX}/${QT_DEPLOY_DATA_DIR}"
+ )
+ foreach(data_file IN LISTS data_files)
+ file(INSTALL "${resources_dir}/${data_file}" DESTINATION "${install_destination}")
+ endforeach()
+endfunction()
+
+# The V8 snapshot file comes as debug or release build. Multi-config builds have both, a self-built
+# Qt might only have the debug one.
+#
+# This function returns the file name of the V8 context snapshot file in ${out_var}.
+# If no snapshot could be found, ${out_var} is the empty string.
+function(_qt_internal_webenginecore_find_v8_context_snapshot out_var)
+ set(no_value_options "")
+ set(single_value_options RESOURCES_DIR)
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ set(result "")
+ set(candidates
+ v8_context_snapshot.bin
+ v8_context_snapshot.debug.bin
+ )
+ if(__QT_DEPLOY_QT_IS_MULTI_CONFIG_BUILD_WITH_DEBUG
+ AND __QT_DEPLOY_ACTIVE_CONFIG STREQUAL "Debug")
+ # Favor the debug version of the snapshot.
+ list(REVERSE candidates)
+ endif()
+ foreach(candidate IN LISTS candidates)
+ if(EXISTS "${arg_RESOURCES_DIR}/${candidate}")
+ set(result "${candidate}")
+ break()
+ endif()
+ endforeach()
+ set("${out_var}" "${result}" PARENT_SCOPE)
+endfunction()
+
+function(_qt_internal_deploy_webenginecore_translations)
+ _qt_internal_webenginecore_status_message("Deploying the WebEngineCore translations")
+
+ get_filename_component(locales_dir "qtwebengine_locales" ABSOLUTE
+ BASE_DIR "${__QT_DEPLOY_QT_INSTALL_PREFIX}/${__QT_DEPLOY_QT_INSTALL_TRANSLATIONS}"
+ )
+ get_filename_component(install_destination "qtwebengine_locales" ABSOLUTE
+ BASE_DIR "${QT_DEPLOY_PREFIX}/${QT_DEPLOY_TRANSLATIONS_DIR}"
+ )
+ file(GLOB locale_files "${locales_dir}/*.pak")
+ foreach(locale_file IN LISTS locale_files)
+ file(INSTALL "${locale_file}" DESTINATION "${install_destination}")
+ endforeach()
+endfunction()
diff --git a/src/core/api/Qt6WebEngineCoreMacros.cmake b/src/core/api/Qt6WebEngineCoreMacros.cmake
index 7e23f377e..8bb731548 100644
--- a/src/core/api/Qt6WebEngineCoreMacros.cmake
+++ b/src/core/api/Qt6WebEngineCoreMacros.cmake
@@ -1,6 +1,12 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
+# Install support uses the CMAKE_INSTALL_xxxDIR variables. Include this here
+# so that it is more likely to get pulled in earlier at a higher level, and also
+# to avoid re-including it many times later
+include(GNUInstallDirs)
+_qt_internal_add_deploy_support("${CMAKE_CURRENT_LIST_DIR}/Qt6WebEngineCoreDeploySupport.cmake")
+
function(qt6_add_webengine_dictionary)
set(options)
set(oneValueArgs TARGET SOURCE OUTPUT_DIRECTORY)
@@ -23,7 +29,7 @@ function(qt6_add_webengine_dictionary)
set(copyCommand COMMAND ${CMAKE_COMMAND} -E copy_directory ${ARGS_OUTPUT_DIRECTORY}/dict
${ARGS_OUTPUT_DIRECTORY}/$<CONFIG>
)
- elseif(isBundle)
+ elseif(APPLE AND isBundle)
get_target_property(outputName ${ARGS_TARGET} OUTPUT_NAME)
if(NOT outputName)
set(outputName ${ARGS_TARGET})
diff --git a/src/core/api/configure.cmake b/src/core/api/configure.cmake
index a35651b8b..f8488c057 100644
--- a/src/core/api/configure.cmake
+++ b/src/core/api/configure.cmake
@@ -7,11 +7,13 @@ if(NOT QT_CONFIGURE_RUNNING)
find_package(GLIB2 COMPONENTS GIO)
find_package(GSSAPI)
find_package(PkgConfig)
- if(PkgConfig_FOUND)
+ if(PkgConfig_FOUND AND QT_FEATURE_pkg_config)
pkg_check_modules(ALSA alsa IMPORTED_TARGET)
pkg_check_modules(PULSEAUDIO libpulse>=0.9.10 libpulse-mainloop-glib)
pkg_check_modules(XDAMAGE xdamage)
pkg_check_modules(POPPLER_CPP poppler-cpp IMPORTED_TARGET)
+ pkg_check_modules(GBM gbm)
+ pkg_check_modules(LIBVA libva>=1.14)
if(NOT GIO_FOUND)
pkg_check_modules(GIO gio-2.0)
endif()
@@ -62,6 +64,10 @@ qt_feature("webengine-system-alsa" PRIVATE
LABEL "Use ALSA"
CONDITION UNIX AND TEST_alsa
)
+qt_feature("webengine-v8-context-snapshot" PRIVATE
+ LABEL "Use v8 context snapshot"
+ AUTODETECT NOT CMAKE_CROSSCOMPILING
+)
qt_feature("webengine-geolocation" PUBLIC
LABEL "Geolocation"
CONDITION TARGET Qt::Positioning
@@ -71,6 +77,12 @@ qt_feature("webengine-system-pulseaudio" PRIVATE
AUTODETECT UNIX
CONDITION PULSEAUDIO_FOUND
)
+qt_feature("webengine-system-gbm" PRIVATE
+ SECTION "WebEngine"
+ LABEL "Use system GBM"
+ AUTODETECT UNIX
+ CONDITION GBM_FOUND
+)
qt_feature("webengine-printing-and-pdf" PRIVATE
LABEL "Printing and PDF"
PURPOSE "Provides printing and output to PDF."
@@ -152,9 +164,26 @@ qt_feature("webengine-vulkan" PRIVATE
PURPOSE "Enables support for Vulkan rendering"
CONDITION QT_FEATURE_vulkan
)
+qt_feature("webengine-vaapi" PRIVATE
+ SECTION "WebEngine"
+ LABEL "VA-API support"
+ PURPOSE "Enables support for VA-API hardware acceleration"
+ AUTODETECT GBM_FOUND AND LIBVA_FOUND AND QT_FEATURE_vulkan
+ # hardware accelerated encoding requires bundled libvpx
+ CONDITION LINUX AND NOT QT_FEATURE_webengine_system_libvpx
+)
+list(LENGTH CMAKE_OSX_ARCHITECTURES osx_arch_count)
+qt_feature("webenginedriver" PUBLIC
+ SECTION "WebEngine"
+ LABEL "Build WebEngineDriver"
+ PURPOSE "Enables WebEngineDriver build"
+ CONDITION NOT CMAKE_CROSSCOMPILING
+ AND NOT (CMAKE_OSX_ARCHITECTURES AND osx_arch_count GREATER 1)
+ DISABLE CMAKE_BUILD_TYPE STREQUAL Debug
+)
# internal testing feature
qt_feature("webengine-system-poppler" PRIVATE
- LABEL "popler"
+ LABEL "poppler"
CONDITION UNIX AND TEST_poppler
)
qt_configure_add_summary_section(NAME "Qt WebEngineCore")
@@ -184,13 +213,19 @@ qt_configure_add_summary_entry(
CONDITION QT_FEATURE_vulkan
)
qt_configure_add_summary_entry(
+ ARGS "webengine-vaapi"
+ CONDITION LINUX
+)
+qt_configure_add_summary_entry(
ARGS "webengine-system-alsa"
- CONDITION UNIX
+ CONDITION LINUX
)
qt_configure_add_summary_entry(
ARGS "webengine-system-pulseaudio"
- CONDITION UNIX
+ CONDITION LINUX
)
+qt_configure_add_summary_entry(ARGS "webengine-v8-context-snapshot")
+qt_configure_add_summary_entry(ARGS "webenginedriver")
qt_configure_end_summary_section() # end of "Qt WebEngineCore" section
if(CMAKE_CROSSCOMPILING)
check_thumb(armThumb)
@@ -208,3 +243,13 @@ qt_configure_add_report_entry(
MESSAGE "WebRTC requires XDamage with qpa_xcb."
CONDITION QT_FEATURE_webengine_ozone_x11 AND NOT XDAMAGE_FOUND
)
+qt_configure_add_report_entry(
+ TYPE WARNING
+ MESSAGE "VA-API is incompatible with system libvpx."
+ CONDITION QT_FEATURE_webengine_system_libvpx AND QT_FEATURE_webengine_vaapi
+)
+qt_configure_add_report_entry(
+ TYPE WARNING
+ MESSAGE "System GBM is disabled. The bundled minigbm supports Intel only, you might need to install libgbm to avoid rendering issues."
+ CONDITION LINUX AND NOT QT_FEATURE_webengine_system_gbm
+)
diff --git a/src/core/api/qtwebenginecoreglobal.cpp b/src/core/api/qtwebenginecoreglobal.cpp
index 1dded1086..d5112ccb3 100644
--- a/src/core/api/qtwebenginecoreglobal.cpp
+++ b/src/core/api/qtwebenginecoreglobal.cpp
@@ -6,44 +6,26 @@
#include <QGuiApplication>
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
-#ifdef Q_OS_MACOS
-#include <sys/types.h>
-#include <sys/sysctl.h>
-#include <QOffscreenSurface>
-#include "macos_context_type_helper.h"
-#endif
#endif
#include <QThread>
#include <QQuickWindow>
#include "web_engine_context.h"
+#include "web_engine_library_info.h"
-#if QT_CONFIG(opengl)
+#include "base/base_paths.h"
+#include "base/i18n/icu_util.h"
+#include "base/path_service.h"
+#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+
+#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS)
QT_BEGIN_NAMESPACE
Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context);
Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context();
QT_END_NAMESPACE
#endif
-#if QT_CONFIG(opengl)
-#ifdef Q_OS_MACOS
-static bool needsOfflineRendererWorkaround()
-{
- size_t hwmodelsize = 0;
-
- if (sysctlbyname("hw.model", nullptr, &hwmodelsize, nullptr, 0) == -1)
- return false;
-
- char hwmodel[hwmodelsize];
- if (sysctlbyname("hw.model", &hwmodel, &hwmodelsize, nullptr, 0) == -1)
- return false;
-
- return QString::fromLatin1(hwmodel) == QLatin1String("MacPro6,1");
-}
-#endif
-#endif
-
namespace QtWebEngineCore {
-#if QT_CONFIG(opengl)
+#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS)
static QOpenGLContext *shareContext;
static void deleteShareContext()
@@ -60,16 +42,20 @@ static void deleteShareContext()
// after the QGuiApplication creation, when AA_ShareOpenGLContexts fills
// the same need but the flag has to be set earlier.
-Q_WEBENGINECORE_PRIVATE_EXPORT void initialize()
+Q_WEBENGINECORE_EXPORT void initialize()
{
-#if QT_CONFIG(opengl)
+#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS)
#ifdef Q_OS_WIN32
qputenv("QT_D3DCREATE_MULTITHREADED", "1");
#endif
-#ifdef Q_OS_MACOS
- if (needsOfflineRendererWorkaround())
- qputenv("QT_MAC_PRO_WEBENGINE_WORKAROUND", "1");
+ auto api = QQuickWindow::graphicsApi();
+ if (api != QSGRendererInterface::OpenGL
+#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
+ && api != QSGRendererInterface::Vulkan && api != QSGRendererInterface::Metal
+ && api != QSGRendererInterface::Direct3D11
#endif
+ )
+ QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
// No need to override the shared context if QApplication already set one (e.g with Qt::AA_ShareOpenGLContexts).
if (!qt_gl_global_share_context()) {
@@ -94,57 +80,6 @@ Q_WEBENGINECORE_PRIVATE_EXPORT void initialize()
shareContext = new QOpenGLContext;
QSurfaceFormat format = QSurfaceFormat::defaultFormat();
-#if defined(Q_OS_MACOS)
- if (format == QSurfaceFormat()) {
- QOpenGLContext testContext;
-
- // Chromium turns off OpenGL for CoreProfiles with versions < 4.1
- // The newest Mac that only supports 3.3 was released in Mid 2011,
- // so it should be safe to request 4.1, but we still double check it
- // works in order not to set an invalid default surface format.
- format.setVersion(4, 1);
- format.setProfile(QSurfaceFormat::CoreProfile);
-
- testContext.setFormat(format);
- if (testContext.create()) {
- QOffscreenSurface surface;
- surface.setFormat(format);
- surface.create();
-
- if (testContext.makeCurrent(&surface)) {
- // The Cocoa QPA integration allows sharing between OpenGL 3.2 and 4.1 contexts,
- // which means even though we requested a 4.1 context, if we only get a 3.2
- // context, it will still work an Chromium will not black list it.
- if (testContext.format().version() >= qMakePair(3, 2)
- && testContext.format().profile() == QSurfaceFormat::CoreProfile
- && !isCurrentContextSoftware()) {
- QSurfaceFormat::setDefaultFormat(format);
- } else {
- qWarning("The available OpenGL surface format was either not version 3.2 "
- "or higher or not a Core Profile.\n"
- "Chromium on macOS will fall back to software rendering in this "
- "case.\n"
- "Hardware acceleration and features such as WebGL will not be "
- "available.");
- format = QSurfaceFormat::defaultFormat();
- }
- testContext.doneCurrent();
- }
- surface.destroy();
- }
- } else {
- // The user explicitly requested a specific surface format that does not fit Chromium's
- // requirements. Warn them about this.
- if (format.version() < qMakePair(3, 2)
- || format.profile() != QSurfaceFormat::CoreProfile) {
- qWarning("An OpenGL surfcace format was requested that is either not version 3.2 "
- "or higher or a not Core Profile.\n"
- "Chromium on macOS will fall back to software rendering in this case.\n"
- "Hardware acceleration and features such as WebGL will not be available.");
- }
- }
-#endif
-
shareContext->setFormat(format);
shareContext->create();
qAddPostRoutine(deleteShareContext);
@@ -154,22 +89,7 @@ Q_WEBENGINECORE_PRIVATE_EXPORT void initialize()
app->setAttribute(Qt::AA_ShareOpenGLContexts);
}
-#if defined(Q_OS_MACOS)
- // Check that the default QSurfaceFormat OpenGL profile is compatible with the global OpenGL
- // shared context profile, otherwise this could lead to a nasty crash.
- QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format();
- QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat();
-
- if (defaultFormat.profile() != sharedFormat.profile()
- && defaultFormat.profile() == QSurfaceFormat::CoreProfile
- && defaultFormat.version() >= qMakePair(3, 2)) {
- qFatal("QWebEngine: Default QSurfaceFormat OpenGL profile is not compatible with the "
- "global shared context OpenGL profile. Please make sure you set a compatible "
- "QSurfaceFormat before the QtGui application instance is created.");
- }
-#endif
-
-#endif // QT_CONFIG(opengl)
+#endif // QT_CONFIG(opengl) && !defined(Q_OS_MACOS)
}
bool closingDown()
@@ -194,27 +114,29 @@ sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterf
#endif
static void initialize()
{
-#if QT_CONFIG(opengl)
- if (QCoreApplication::instance()) {
- // On Windows/ANGLE, calling QtWebEngineQuick::initialize from DllMain will result in a
- // crash.
- if (!qt_gl_global_share_context()
- && !(QCoreApplication::testAttribute(Qt::AA_ShareOpenGLContexts)
- && QQuickWindow::graphicsApi() == QSGRendererInterface::OpenGLRhi)) {
- qWarning("Qt WebEngine seems to be initialized from a plugin. Please "
- "set Qt::AA_ShareOpenGLContexts using QCoreApplication::setAttribute and "
- "QSGRendererInterface::OpenGLRhi using QQuickWindow::setGraphicsApi "
- "before constructing QGuiApplication.");
- }
- return;
- }
-
+#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS)
// QCoreApplication is not yet instantiated, ensuring the call will be deferred
qAddPreRoutine(QtWebEngineCore::initialize);
- auto api = QQuickWindow::graphicsApi();
- if (api != QSGRendererInterface::OpenGLRhi && api != QSGRendererInterface::VulkanRhi)
- QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi);
#endif // QT_CONFIG(opengl)
}
+QT_BEGIN_NAMESPACE
+
+QString qWebEngineGetDomainAndRegistry(const QUrl &url) {
+ base::FilePath icuDataPath;
+ // Let's assume that ICU is already initialized if DIR_QT_LIBRARY_DATA is set.
+ if (!base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &icuDataPath)) {
+ icuDataPath = WebEngineLibraryInfo::getPath(base::DIR_QT_LIBRARY_DATA);
+ if (!base::PathService::OverrideAndCreateIfNeeded(base::DIR_QT_LIBRARY_DATA, icuDataPath, false, false))
+ qWarning("Failed to set ICU data path.");
+ base::i18n::InitializeICU();
+ }
+
+ const QString host = url.host();
+ const std::string domain = net::registry_controlled_domains::GetDomainAndRegistry(host.toStdString(), net::registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES);
+ return QString::fromStdString(domain);
+}
+
+QT_END_NAMESPACE
+
Q_CONSTRUCTOR_FUNCTION(initialize)
diff --git a/src/core/api/qtwebenginecoreglobal.h b/src/core/api/qtwebenginecoreglobal.h
index 305040808..0041a72be 100644
--- a/src/core/api/qtwebenginecoreglobal.h
+++ b/src/core/api/qtwebenginecoreglobal.h
@@ -9,6 +9,8 @@
QT_BEGIN_NAMESPACE
+class QUrl;
+
#if defined(BUILDING_CHROMIUM)
# define Q_WEBENGINECORE_EXPORT Q_DECL_EXPORT
#else
@@ -18,9 +20,12 @@ QT_BEGIN_NAMESPACE
#define ASSERT_ENUMS_MATCH(A, B) Q_STATIC_ASSERT_X(static_cast<int>(A) == static_cast<int>(B), "The enum values must match");
Q_WEBENGINECORE_EXPORT Q_DECL_CONST_FUNCTION const char *qWebEngineVersion() noexcept;
+Q_WEBENGINECORE_EXPORT Q_DECL_CONST_FUNCTION const char *qWebEngineProcessName() noexcept;
Q_WEBENGINECORE_EXPORT Q_DECL_CONST_FUNCTION const char *qWebEngineChromiumVersion() noexcept;
Q_WEBENGINECORE_EXPORT Q_DECL_CONST_FUNCTION const char *qWebEngineChromiumSecurityPatchVersion() noexcept;
+Q_WEBENGINECORE_EXPORT QString qWebEngineGetDomainAndRegistry(const QUrl &url);
+
QT_END_NAMESPACE
#endif // QTWEBENGINECOREGLOBAL_H
diff --git a/src/core/api/qtwebenginecoreglobal_p.h b/src/core/api/qtwebenginecoreglobal_p.h
index 6bd1c5a06..a63568c8a 100644
--- a/src/core/api/qtwebenginecoreglobal_p.h
+++ b/src/core/api/qtwebenginecoreglobal_p.h
@@ -27,18 +27,16 @@
#define QT_NOT_USED Q_UNREACHABLE(); // This will assert in debug.
#endif
-#define Q_WEBENGINECORE_PRIVATE_EXPORT Q_WEBENGINECORE_EXPORT
-
namespace QtWebEngineCore {
-Q_WEBENGINECORE_PRIVATE_EXPORT int processMain(int argc, const char **argv);
-Q_WEBENGINECORE_PRIVATE_EXPORT bool closingDown();
+Q_WEBENGINECORE_EXPORT int processMain(int argc, const char **argv);
+Q_WEBENGINECORE_EXPORT bool closingDown();
} // namespace
#if defined(Q_OS_WIN)
namespace sandbox {
struct SandboxInterfaceInfo;
}
namespace QtWebEngineSandbox {
-Q_WEBENGINECORE_PRIVATE_EXPORT sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterfaceInfo *info = nullptr);
+Q_WEBENGINECORE_EXPORT sandbox::SandboxInterfaceInfo *staticSandboxInterfaceInfo(sandbox::SandboxInterfaceInfo *info = nullptr);
void initializeStaticCopy(int argc, const char **argv);
}
#endif
diff --git a/src/core/api/qwebengineclienthints.cpp b/src/core/api/qwebengineclienthints.cpp
new file mode 100644
index 000000000..907d4ae76
--- /dev/null
+++ b/src/core/api/qwebengineclienthints.cpp
@@ -0,0 +1,211 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwebengineclienthints.h"
+
+#include "profile_adapter.h"
+
+#include <QJsonObject>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QWebEngineClientHints
+ \brief The QWebEngineClientHints class provides an object to customize User-Agent Client Hints used by a profile.
+
+ \since 6.8
+
+ \inmodule QtWebEngineCore
+
+ QWebEngineClientHints allows configuration of exposing browser and platform information via
+ User-Agent response and request headers, and a JavaScript API.
+
+ The information accessed via this API is split into two groups: low entropy and high entropy hints.
+ Low entropy hints (\l{QWebEngineClientHints::platform}{platform} and \l{QWebEngineClientHints::mobile}{mobile})
+ are those that do not give away much information; the API makes these accessible with every request and they can not
+ be disabled by QWebEngineClientHints::setAllClientHintsEnabled.
+
+ All the others are high entropy hints; they have the potential to give away more information, therefore they can be
+ disabled by QWebEngineClientHints::setAllClientHintsEnabled.
+
+ Each profile object has its own QWebEngineClientHints object, which configures the
+ Client Hint settings for that browsing context. If a Client Hint is not configured for a web engine
+ profile, its default value is deduced from the system.
+
+ \sa QWebEngineProfile::clientHints(), QQuickWebEngineProfile::clientHints()
+*/
+
+QWebEngineClientHints::QWebEngineClientHints(QtWebEngineCore::ProfileAdapter *profileAdapter)
+ : m_profileAdapter(profileAdapter)
+{
+}
+
+QWebEngineClientHints::~QWebEngineClientHints()
+{
+}
+
+/*!
+ \property QWebEngineClientHints::arch
+ The value of the \c{Sec-CH-UA-Arch} HTTP header and \c{architecture} member of NavigatorUAData in JavaScript.
+*/
+QString QWebEngineClientHints::arch() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAArchitecture).toString();
+}
+
+/*!
+ \property QWebEngineClientHints::platform
+ The value of the \c{Sec-CH-UA-Platform} HTTP header and \c{platform} member of NavigatorUAData in JavaScript.
+
+ Can not be disabled.
+*/
+QString QWebEngineClientHints::platform() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAPlatform).toString();
+}
+
+/*!
+ \property QWebEngineClientHints::model
+ The value of the \c{Sec-CH-UA-Model} HTTP header and \c{model} member of NavigatorUAData in JavaScript.
+*/
+QString QWebEngineClientHints::model() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAModel).toString();
+}
+
+/*!
+ \property QWebEngineClientHints::mobile
+ The value of the \c{Sec-CH-UA-Mobile} HTTP header and \c{mobile} member of NavigatorUAData in JavaScript.
+
+ Can not be disabled.
+*/
+bool QWebEngineClientHints::isMobile() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAMobile).toBool();
+}
+
+/*!
+ \property QWebEngineClientHints::fullVersion
+ The value of the \c{Sec-CH-UA-Full-Version} HTTP header and \c{uaFullVersion} member of NavigatorUAData in JavaScript.
+*/
+QString QWebEngineClientHints::fullVersion() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAFullVersion).toString();
+}
+
+/*!
+ \property QWebEngineClientHints::platformVersion
+ The value of the \c{Sec-CH-UA-Platform-Version} HTTP header and \c{platformVersion} member of NavigatorUAData in JavaScript.
+*/
+QString QWebEngineClientHints::platformVersion() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAPlatformVersion).toString();
+}
+
+/*!
+ \property QWebEngineClientHints::bitness
+ The value of the \c{Sec-CH-UA-Bitness} HTTP header and \c{bitness} member of NavigatorUAData in JavaScript.
+*/
+QString QWebEngineClientHints::bitness() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UABitness).toString();
+}
+
+/*!
+ \property QWebEngineClientHints::fullVersionList
+ The value of the \c{Sec-CH-UA-Full-Version-List} HTTP header and \c{fullVersionList} member of NavigatorUAData in JavaScript.
+
+ It holds brand name and version number pairs in a QHash. The provided values will be automatically extended by the currently used version
+ of Chromium and a semi-random brand.
+*/
+QHash<QString,QString> QWebEngineClientHints::fullVersionList() const
+{
+ QHash<QString, QString> ret;
+ QJsonObject fullVersionList = m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAFullVersionList).toJsonObject();
+ for (const QString &key : fullVersionList.keys())
+ ret.insert(key, fullVersionList.value(key).toString());
+ return ret;
+}
+
+/*!
+ \property QWebEngineClientHints::wow64
+ The value of the \c{Sec-CH-UA-Wow64} HTTP header and \c{wow64} member of NavigatorUAData in JavaScript.
+*/
+bool QWebEngineClientHints::isWow64() const
+{
+ return m_profileAdapter->clientHint(QtWebEngineCore::ProfileAdapter::UAWOW64).toBool();
+}
+
+void QWebEngineClientHints::setArch(const QString &arch)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAArchitecture, QVariant(arch));
+}
+
+void QWebEngineClientHints::setPlatform(const QString &platform)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAPlatform, QVariant(platform));
+}
+
+void QWebEngineClientHints::setModel(const QString &model)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAModel, QVariant(model));
+}
+
+void QWebEngineClientHints::setIsMobile(const bool mobile)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAMobile, QVariant(mobile));
+}
+
+void QWebEngineClientHints::setFullVersion(const QString &fullVerson)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAFullVersion, QVariant(fullVerson));
+}
+
+void QWebEngineClientHints::setPlatformVersion(const QString &platformVersion)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAPlatformVersion, QVariant(platformVersion));
+}
+
+void QWebEngineClientHints::setBitness(const QString &bitness)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UABitness, QVariant(bitness));
+}
+
+void QWebEngineClientHints::setFullVersionList(const QHash<QString,QString> &fullVersionList)
+{
+ QJsonObject jsonObject;
+ for (auto i = fullVersionList.cbegin(), end = fullVersionList.cend(); i != end; ++i)
+ jsonObject.insert(i.key(), QJsonValue(i.value()));
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAFullVersionList, QVariant(jsonObject));
+}
+
+void QWebEngineClientHints::setIsWow64(const bool wow64)
+{
+ m_profileAdapter->setClientHint(QtWebEngineCore::ProfileAdapter::UAWOW64, QVariant(wow64));
+}
+
+/*!
+ \property QWebEngineClientHints::isAllClientHintsEnabled
+ This property controls whether the Client Hints HTTP headers are sent by WebEngine or not.
+
+ Enabled by default.
+*/
+bool QWebEngineClientHints::isAllClientHintsEnabled()
+{
+ return m_profileAdapter->clientHintsEnabled();
+}
+
+void QWebEngineClientHints::setAllClientHintsEnabled(bool enabled)
+{
+ m_profileAdapter->setClientHintsEnabled(enabled);
+}
+
+/*!
+ Resets all Client Hints settings to their default values.
+*/
+void QWebEngineClientHints::resetAll()
+{
+ m_profileAdapter->resetClientHints();
+}
+
+QT_END_NAMESPACE
diff --git a/src/core/api/qwebengineclienthints.h b/src/core/api/qwebengineclienthints.h
new file mode 100644
index 000000000..8956b5cb6
--- /dev/null
+++ b/src/core/api/qwebengineclienthints.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINECLIENTHINTS_H
+#define QWEBENGINECLIENTHINTS_H
+
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qhash.h>
+
+namespace QtWebEngineCore {
+class ProfileAdapter;
+}
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBENGINECORE_EXPORT QWebEngineClientHints
+{
+ Q_GADGET
+ Q_PROPERTY(QString arch READ arch WRITE setArch)
+ Q_PROPERTY(QString platform READ platform WRITE setPlatform)
+ Q_PROPERTY(QString model READ model WRITE setModel)
+ Q_PROPERTY(bool mobile READ isMobile WRITE setIsMobile)
+ Q_PROPERTY(QString fullVersion READ fullVersion WRITE setFullVersion)
+ Q_PROPERTY(QString platformVersion READ platformVersion WRITE setPlatformVersion)
+ Q_PROPERTY(QString bitness READ bitness WRITE setBitness)
+ Q_PROPERTY(QHash<QString,QString> fullVersionList READ fullVersionList WRITE setFullVersionList)
+ Q_PROPERTY(bool wow64 READ isWow64 WRITE setIsWow64)
+
+ Q_PROPERTY(bool isAllClientHintsEnabled READ isAllClientHintsEnabled WRITE setAllClientHintsEnabled)
+
+public:
+ ~QWebEngineClientHints();
+
+ QString arch() const;
+ QString platform() const;
+ QString model() const;
+ bool isMobile() const;
+ QString fullVersion() const;
+ QString platformVersion() const;
+ QString bitness() const;
+ QHash<QString,QString> fullVersionList() const;
+ bool isWow64() const;
+
+ void setArch(const QString &);
+ void setPlatform(const QString &);
+ void setModel(const QString &);
+ void setIsMobile(const bool);
+ void setFullVersion(const QString &);
+ void setPlatformVersion(const QString &);
+ void setBitness(const QString &);
+ void setFullVersionList(const QHash<QString,QString> &);
+ void setIsWow64(const bool);
+
+ bool isAllClientHintsEnabled();
+ void setAllClientHintsEnabled(bool enabled);
+
+ void resetAll();
+
+private:
+ explicit QWebEngineClientHints(QtWebEngineCore::ProfileAdapter *profileAdapter);
+ Q_DISABLE_COPY(QWebEngineClientHints)
+ friend class QWebEngineProfilePrivate;
+ friend class QQuickWebEngineProfilePrivate;
+
+ QtWebEngineCore::ProfileAdapter *m_profileAdapter;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINECLIENTHINTS_H
diff --git a/src/core/api/qwebenginecookiestore_p.h b/src/core/api/qwebenginecookiestore_p.h
index ac9395301..51200436d 100644
--- a/src/core/api/qwebenginecookiestore_p.h
+++ b/src/core/api/qwebenginecookiestore_p.h
@@ -29,7 +29,7 @@ class CookieMonsterDelegateQt;
QT_BEGIN_NAMESPACE
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineCookieStorePrivate
+class Q_WEBENGINECORE_EXPORT QWebEngineCookieStorePrivate
{
Q_DECLARE_PUBLIC(QWebEngineCookieStore)
struct CookieData {
diff --git a/src/core/api/qwebenginedesktopmediarequest.cpp b/src/core/api/qwebenginedesktopmediarequest.cpp
new file mode 100644
index 000000000..dae69a68c
--- /dev/null
+++ b/src/core/api/qwebenginedesktopmediarequest.cpp
@@ -0,0 +1,206 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "desktop_media_controller.h"
+#include "qwebenginedesktopmediarequest.h"
+#include "qwebenginedesktopmediarequest_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QWebEngineDesktopMediaRequestPrivate)
+
+/*!
+ \class QWebEngineDesktopMediaRequest
+ \brief A request for populating a dialog with available sources for screen capturing.
+
+ \since 6.7
+
+ \inmodule QtWebEngineCore
+
+ To allow web applications to capture contents of a display, applications must connect
+ to QWebEnginePage::desktopMediaRequested, which takes a QWebEngineDesktopMediaRequest
+ instance as an argument.
+
+ If a web application requests access to the contents of a display,
+ QWebEnginePage::desktopMediaRequested will be emitted with a
+ QWebEngineDesktopMediaRequest instance as an argument which holds references to
+ QAbstractListModels for available windows and screens that can be captured.
+
+ The data model's \e Qt::DisplayRole specifies the name of the source which is the title of a
+ window or the number of the display.
+ The model is dynamically updates if the available list of sources has changed e.g a window is
+ opened/closed.
+
+ The signal handler needs to then either call QWebEngineDesktopMediaRequest:selectScreen() or
+ QWebEngineDesktopMediaRequest::selectWindow() to accept the request and start screensharing.
+ \sa QWebEnginePage::desktopMediaRequested().
+*/
+
+class QWebEngineMediaSourceModel : public QAbstractListModel
+{
+public:
+ ~QWebEngineMediaSourceModel() override;
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
+
+private:
+ friend class QWebEngineDesktopMediaRequestPrivate;
+ explicit QWebEngineMediaSourceModel(QtWebEngineCore::DesktopMediaListQt *mediaList);
+ QtWebEngineCore::DesktopMediaListQt *m_mediaList;
+};
+
+QWebEngineMediaSourceModel::QWebEngineMediaSourceModel(QtWebEngineCore::DesktopMediaListQt *mediaList)
+ : m_mediaList(mediaList)
+{
+ QObject::connect(m_mediaList, &QtWebEngineCore::DesktopMediaListQt::sourceAdded, this,
+ [this](int index) {
+ beginInsertRows(QModelIndex(), index, index);
+ endInsertRows();
+ });
+ QObject::connect(m_mediaList, &QtWebEngineCore::DesktopMediaListQt::sourceRemoved, this,
+ [this](int index) {
+ beginRemoveRows(QModelIndex(), index, index);
+ endRemoveRows();
+ });
+ QObject::connect(m_mediaList, &QtWebEngineCore::DesktopMediaListQt::sourceMoved, this,
+ [this](int oldIndex, int newIndex) {
+ beginMoveRows(QModelIndex(), oldIndex, oldIndex, QModelIndex(), newIndex);
+ endMoveRows();
+ });
+ QObject::connect(m_mediaList, &QtWebEngineCore::DesktopMediaListQt::sourceNameChanged, this,
+ [this](int index) {
+ Q_EMIT dataChanged(QModelIndex(), QModelIndex(),
+ { Qt::DisplayRole });
+ });
+}
+
+QWebEngineMediaSourceModel::~QWebEngineMediaSourceModel() { }
+
+int QWebEngineMediaSourceModel::rowCount(const QModelIndex &) const
+{
+ return m_mediaList->getSourceCount();
+}
+
+QVariant QWebEngineMediaSourceModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+ switch (role) {
+ case Qt::DisplayRole:
+ case Qt::EditRole:
+ return m_mediaList->getSourceName(index.row());
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+QWebEngineDesktopMediaRequestPrivate::QWebEngineDesktopMediaRequestPrivate(
+ QtWebEngineCore::DesktopMediaController *controller)
+ : controller(controller)
+ , m_screensModel(new QWebEngineMediaSourceModel(controller->screens()))
+ , m_windowsModel(new QWebEngineMediaSourceModel(controller->windows()))
+{
+}
+
+QWebEngineDesktopMediaRequestPrivate::~QWebEngineDesktopMediaRequestPrivate()
+{
+ // Keep old behavior, if there were no user action select the primary screen.
+ if (!didSelectOrCancel)
+ controller->selectScreen(0);
+}
+
+void QWebEngineDesktopMediaRequestPrivate::selectWindow(const QModelIndex &index)
+{
+ Q_ASSERT(index.model() == m_windowsModel.get());
+ if (!index.isValid())
+ return;
+ didSelectOrCancel = true;
+ controller->selectWindow(index.row());
+}
+
+void QWebEngineDesktopMediaRequestPrivate::selectScreen(const QModelIndex &index)
+{
+ Q_ASSERT(index.model() == m_screensModel.get());
+ if (!index.isValid())
+ return;
+ didSelectOrCancel = true;
+ controller->selectScreen(index.row());
+}
+
+void QWebEngineDesktopMediaRequestPrivate::cancel()
+{
+ // Notifies webrtc so it can free up it's resources.
+ didSelectOrCancel = true;
+ controller->cancel();
+}
+
+QWebEngineDesktopMediaRequest::QWebEngineDesktopMediaRequest(
+ QtWebEngineCore::DesktopMediaController *controller)
+ : d(new QWebEngineDesktopMediaRequestPrivate(controller))
+{
+}
+
+QWebEngineDesktopMediaRequest::~QWebEngineDesktopMediaRequest() = default;
+
+QWebEngineDesktopMediaRequest::QWebEngineDesktopMediaRequest(
+ const QWebEngineDesktopMediaRequest &other) noexcept = default;
+
+QWebEngineDesktopMediaRequest &QWebEngineDesktopMediaRequest::operator=(
+ const QWebEngineDesktopMediaRequest &other) noexcept = default;
+
+QWebEngineDesktopMediaRequest::QWebEngineDesktopMediaRequest(
+ QWebEngineDesktopMediaRequest &&other) noexcept = default;
+
+/*!
+ Returns a QAbstractListModel for the available screens.
+
+ \sa windowsModel()
+*/
+QAbstractListModel *QWebEngineDesktopMediaRequest::screensModel() const
+{
+ return d->m_screensModel.get();
+}
+
+/*!
+ Returns a QAbstractListModel for the available windows.
+
+ \sa screensModel()
+*/
+QAbstractListModel *QWebEngineDesktopMediaRequest::windowsModel() const
+{
+ return d->m_windowsModel.get();
+}
+
+/*!
+ Selects the window on the \a index to be captured.
+
+ \sa QWebEngineDesktopMediaRequest::selectScreen()
+*/
+void QWebEngineDesktopMediaRequest::selectWindow(const QModelIndex &index) const
+{
+ d->selectWindow(index);
+}
+
+/*!
+ Selects the screen on the \a index to be captured.
+
+ \sa QWebEngineDesktopMediaRequest::selectWindow()
+*/
+void QWebEngineDesktopMediaRequest::selectScreen(const QModelIndex &index) const
+{
+ d->selectScreen(index);
+}
+
+/*!
+ Rejects a request. Screen capturing will be aborted.
+*/
+void QWebEngineDesktopMediaRequest::cancel() const
+{
+ d->cancel();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qwebenginedesktopmediarequest.cpp"
diff --git a/src/core/api/qwebenginedesktopmediarequest.h b/src/core/api/qwebenginedesktopmediarequest.h
new file mode 100644
index 000000000..ebf66bce4
--- /dev/null
+++ b/src/core/api/qwebenginedesktopmediarequest.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINEDESKTOPMEDIAREQUEST_H
+#define QWEBENGINEDESKTOPMEDIAREQUEST_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/qshareddata.h>
+#include <QtCore/qobject.h>
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+
+namespace QtWebEngineCore {
+class DesktopMediaController;
+}
+
+QT_BEGIN_NAMESPACE
+class QWebEnginePagePrivate;
+class QQuickWebEngineViewPrivate;
+class QWebEngineDesktopMediaRequestPrivate;
+QT_DECLARE_QESDP_SPECIALIZATION_DTOR_WITH_EXPORT(QWebEngineDesktopMediaRequestPrivate,
+ Q_WEBENGINECORE_EXPORT)
+
+class QWebEngineDesktopMediaRequest
+{
+ Q_GADGET_EXPORT(Q_WEBENGINECORE_EXPORT)
+ Q_PROPERTY(QAbstractListModel *screensModel READ screensModel FINAL)
+ Q_PROPERTY(QAbstractListModel *windowsModel READ windowsModel FINAL)
+
+public:
+ Q_WEBENGINECORE_EXPORT ~QWebEngineDesktopMediaRequest();
+
+ Q_WEBENGINECORE_EXPORT
+ QWebEngineDesktopMediaRequest(const QWebEngineDesktopMediaRequest &other) noexcept;
+ Q_WEBENGINECORE_EXPORT
+ QWebEngineDesktopMediaRequest(QWebEngineDesktopMediaRequest &&other) noexcept;
+ Q_WEBENGINECORE_EXPORT
+ QWebEngineDesktopMediaRequest &operator=(const QWebEngineDesktopMediaRequest &other) noexcept;
+ QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QWebEngineDesktopMediaRequest)
+ void swap(QWebEngineDesktopMediaRequest &other) noexcept { d.swap(other.d); }
+
+ Q_WEBENGINECORE_EXPORT QAbstractListModel *screensModel() const;
+ Q_WEBENGINECORE_EXPORT QAbstractListModel *windowsModel() const;
+
+ Q_WEBENGINECORE_EXPORT Q_INVOKABLE void selectScreen(const QModelIndex &index) const;
+ Q_WEBENGINECORE_EXPORT Q_INVOKABLE void selectWindow(const QModelIndex &index) const;
+ Q_WEBENGINECORE_EXPORT Q_INVOKABLE void cancel() const;
+
+private:
+ friend class QWebEnginePagePrivate;
+ friend class QQuickWebEngineViewPrivate;
+ Q_WEBENGINECORE_EXPORT explicit QWebEngineDesktopMediaRequest(
+ QtWebEngineCore::DesktopMediaController *controller);
+ QExplicitlySharedDataPointer<QWebEngineDesktopMediaRequestPrivate> d;
+};
+Q_DECLARE_SHARED(QWebEngineDesktopMediaRequest)
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEDESKTOPMEDIAREQUEST_H
diff --git a/src/core/api/qwebenginedesktopmediarequest_p.h b/src/core/api/qwebenginedesktopmediarequest_p.h
new file mode 100644
index 000000000..3add71bc0
--- /dev/null
+++ b/src/core/api/qwebenginedesktopmediarequest_p.h
@@ -0,0 +1,49 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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.
+//
+
+#ifndef QWEBENGINEDESKTOPMEDIAREQUEST_P_H
+#define QWEBENGINEDESKTOPMEDIAREQUEST_P_H
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtCore/QSharedData>
+#include <QtCore/qobject.h>
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+
+namespace QtWebEngineCore {
+class DesktopMediaController;
+}
+
+QT_BEGIN_NAMESPACE
+class QWebEngineMediaSourceModel;
+
+class QWebEngineDesktopMediaRequestPrivate : public QSharedData
+{
+public:
+ ~QWebEngineDesktopMediaRequestPrivate();
+ explicit QWebEngineDesktopMediaRequestPrivate(
+ QtWebEngineCore::DesktopMediaController *controller);
+
+ void selectScreen(const QModelIndex &index);
+ void selectWindow(const QModelIndex &index);
+ void cancel();
+
+ bool didSelectOrCancel = false;
+ std::unique_ptr<QtWebEngineCore::DesktopMediaController> controller;
+ std::unique_ptr<QWebEngineMediaSourceModel> m_screensModel;
+ std::unique_ptr<QWebEngineMediaSourceModel> m_windowsModel;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEDESKTOPMEDIAREQUEST_P_H
diff --git a/src/core/api/qwebenginedownloadrequest.cpp b/src/core/api/qwebenginedownloadrequest.cpp
index 97f6051b4..cbf46b448 100644
--- a/src/core/api/qwebenginedownloadrequest.cpp
+++ b/src/core/api/qwebenginedownloadrequest.cpp
@@ -123,20 +123,9 @@ static inline QWebEngineDownloadRequest::DownloadInterruptReason toDownloadInter
QWebEnginePage::download, QWebEnginePage::save
*/
-QWebEngineDownloadRequestPrivate::QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter, const QUrl &url)
- : downloadFinished(false)
- , downloadId(-1)
- , downloadState(QWebEngineDownloadRequest::DownloadCancelled)
- , savePageFormat(QWebEngineDownloadRequest::MimeHtmlSaveFormat)
- , interruptReason(QWebEngineDownloadRequest::NoReason)
- , downloadUrl(url)
- , downloadPaused(false)
- , isCustomFileName(false)
- , totalBytes(-1)
- , receivedBytes(0)
- , isSavePageDownload(false)
- , profileAdapter(adapter)
- , adapterClient(nullptr)
+QWebEngineDownloadRequestPrivate::QWebEngineDownloadRequestPrivate(
+ QtWebEngineCore::ProfileAdapter *adapter)
+ : profileAdapter(adapter)
{
}
@@ -230,16 +219,22 @@ void QWebEngineDownloadRequest::cancel()
QWebEngineDownloadRequest::DownloadState state = d->downloadState;
- if (state == QWebEngineDownloadRequest::DownloadCompleted
- || state == QWebEngineDownloadRequest::DownloadCancelled)
+ if (state == QWebEngineDownloadRequest::DownloadCompleted)
return;
- // We directly cancel the download request if the user cancels
- // before it even started, so no need to notify the profile here.
+ bool cancelled = state == QWebEngineDownloadRequest::DownloadCancelled;
+ if (cancelled)
+ return;
+
+ // Check if the download manager has a DownloadItem for this ID
+ // (network downloads or in progress page/resource saves)
if (state == QWebEngineDownloadRequest::DownloadInProgress) {
if (d->profileAdapter)
- d->profileAdapter->cancelDownload(d->downloadId);
- } else {
+ cancelled = d->profileAdapter->cancelDownload(d->downloadId);
+ }
+
+ // Not cancelled downloads are not even started yet at this point
+ if (!cancelled) {
d->downloadState = QWebEngineDownloadRequest::DownloadCancelled;
Q_EMIT stateChanged(d->downloadState);
d->setFinished();
@@ -391,7 +386,7 @@ QWebEngineDownloadRequest::DownloadState QWebEngineDownloadRequest::state() cons
}
/*!
- Returns the the total amount of data to download in bytes.
+ Returns the total amount of data to download in bytes.
\c -1 means the size is unknown.
*/
@@ -612,7 +607,7 @@ QString QWebEngineDownloadRequest::interruptReasonString() const
QWebEnginePage *QWebEngineDownloadRequest::page() const
{
Q_D(const QWebEngineDownloadRequest);
- if (d->adapterClient->clientType() == QtWebEngineCore::WebContentsAdapterClient::WidgetsClient)
+ if (d->adapterClient && d->adapterClient->clientType() == QtWebEngineCore::WebContentsAdapterClient::WidgetsClient)
return const_cast<QWebEnginePage *>(static_cast<const QWebEnginePage *>(d->adapterClient->holdingQObject()));
return nullptr;
}
diff --git a/src/core/api/qwebenginedownloadrequest_p.h b/src/core/api/qwebenginedownloadrequest_p.h
index 814af59cb..eef6c9bb5 100644
--- a/src/core/api/qwebenginedownloadrequest_p.h
+++ b/src/core/api/qwebenginedownloadrequest_p.h
@@ -28,35 +28,38 @@ class WebContentsAdapterClient;
QT_BEGIN_NAMESPACE
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineDownloadRequestPrivate
+class Q_WEBENGINECORE_EXPORT QWebEngineDownloadRequestPrivate
{
public:
- QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter, const QUrl &url);
+ QWebEngineDownloadRequestPrivate(QtWebEngineCore::ProfileAdapter *adapter);
~QWebEngineDownloadRequestPrivate();
void update(const QtWebEngineCore::ProfileAdapterClient::DownloadItemInfo &info);
void setFinished();
- bool downloadFinished;
- quint32 downloadId;
+ bool downloadFinished = false;
+ quint32 downloadId = -1;
qint64 startTime;
- QWebEngineDownloadRequest::DownloadState downloadState;
- QWebEngineDownloadRequest::SavePageFormat savePageFormat;
- QWebEngineDownloadRequest::DownloadInterruptReason interruptReason;
+ QWebEngineDownloadRequest::DownloadState downloadState =
+ QWebEngineDownloadRequest::DownloadCancelled;
+ QWebEngineDownloadRequest::SavePageFormat savePageFormat =
+ QWebEngineDownloadRequest::MimeHtmlSaveFormat;
+ QWebEngineDownloadRequest::DownloadInterruptReason interruptReason =
+ QWebEngineDownloadRequest::NoReason;
QString downloadPath;
- const QUrl downloadUrl;
+ QUrl downloadUrl;
QString mimeType;
- bool downloadPaused;
+ bool downloadPaused = false;
QString suggestedFileName;
QString downloadDirectory;
QString downloadFileName;
- bool isCustomFileName;
- qint64 totalBytes;
- qint64 receivedBytes;
- bool isSavePageDownload;
+ bool isCustomFileName = false;
+ qint64 totalBytes = -1;
+ qint64 receivedBytes = 0;
+ bool isSavePageDownload = false;
QWebEngineDownloadRequest *q_ptr;
QPointer<QtWebEngineCore::ProfileAdapter> profileAdapter;
- QtWebEngineCore::WebContentsAdapterClient *adapterClient;
+ QtWebEngineCore::WebContentsAdapterClient *adapterClient = nullptr;
Q_DECLARE_PUBLIC(QWebEngineDownloadRequest)
};
diff --git a/src/core/api/qwebenginefilesystemaccessrequest.cpp b/src/core/api/qwebenginefilesystemaccessrequest.cpp
index 6527e1766..3f901b671 100644
--- a/src/core/api/qwebenginefilesystemaccessrequest.cpp
+++ b/src/core/api/qwebenginefilesystemaccessrequest.cpp
@@ -27,6 +27,25 @@ QT_BEGIN_NAMESPACE
either call accept() or reject().
*/
+/*!
+ \enum QWebEngineFileSystemAccessRequest::AccessFlag
+
+ This enum describes the type of the requested access: read, write or both. The options
+ can be OR-ed together from the following list:
+
+ \value Read
+ \value Write
+*/
+
+/*!
+ \enum QWebEngineFileSystemAccessRequest::HandleType
+
+ This enum describes the type of the requested file system entry.
+
+ \value File
+ \value Directory
+*/
+
QWebEngineFileSystemAccessRequest::QWebEngineFileSystemAccessRequest(
const QWebEngineFileSystemAccessRequest &other) = default;
QWebEngineFileSystemAccessRequest &QWebEngineFileSystemAccessRequest::operator=(
diff --git a/src/core/api/qwebengineglobalsettings.cpp b/src/core/api/qwebengineglobalsettings.cpp
new file mode 100644
index 000000000..6aadd5517
--- /dev/null
+++ b/src/core/api/qwebengineglobalsettings.cpp
@@ -0,0 +1,125 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwebengineglobalsettings.h"
+#include "qwebengineglobalsettings_p.h"
+#include <QDebug>
+
+#ifdef signals
+#undef signals
+#endif
+
+namespace QtWebEngineCore {
+extern void configureStubHostResolver(QWebEngineGlobalSettings::SecureDnsMode dnsMode,
+ std::string dnsOverHttpsTemplates, bool insecureDnsClientEnabled,
+ bool additionalInsecureDnsTypesEnabled);
+extern bool isValidTemplates(std::string templates);
+
+} // namespace QtWebEngineCore
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \namespace QWebEngineGlobalSettings
+ \brief The QWebEngineGlobalSettings namespace holds global settings of the web engine.
+ \since 6.6
+ \inmodule QtWebEngineCore
+
+ The QWebEngineGlobalSettings namespace holds global properties of the web engine.
+
+ Invoke setDnsMode() to configure DNS-over-HTTPS.
+
+ \sa QWebEngineGlobalSettings::setDnsMode()
+*/
+
+/*!
+ \enum QWebEngineGlobalSettings::SecureDnsMode
+
+ This enum sets the DNS-over-HTTPS mode used by the DnsMode structure:
+
+ \value SystemOnly This is the default. Use the system DNS host resolution.
+ \value SecureWithFallback Enable DNS-over-HTTPS (DoH). DoH servers have to be
+ provided through \l {QWebEngineGlobalSettings::DnsMode::serverTemplates}{serverTemplates} in
+ the DnsMode structure. If a host cannot be resolved via the provided servers,
+ the system DNS host resolution is used.
+ \value SecureOnly Enable DNS-over-HTTPS and only allow hosts to be resolved
+ this way. DoH servers have to be provided through
+ \l {QWebEngineGlobalSettings::DnsMode::serverTemplates}{serverTemplates} in the DnsMode
+ structure. If the DNS-over-HTTPS resolution fails, there is no fallback and the DNS host
+ resolution fails completely.
+*/
+
+/*!
+ \class QWebEngineGlobalSettings::DnsMode
+ \brief The DnsMode struct provides means to specify the DNS host resolution mode.
+ \since 6.6
+ \inmodule QtWebEngineCore
+
+ The QWebEngineGlobalSettings::DnsMode structure describes the DNS mode and
+ the associated DNS server template used for the DNS host resolution.
+*/
+
+/*!
+ \variable QWebEngineGlobalSettings::DnsMode::secureMode
+ \brief The DNS mode used for the host resolution.
+
+ Set \a secureMode to SecureDnsMode::SecureOnly to only allow DNS-over-HTTPS host resolution
+ using servers from \a serverTemplates.
+
+ Set \a secureMode to SecureDnsMode::SecureWithFallback to enable DNS-over-HTTPS host resolution
+ using servers from \a serverTemplates, with a fallback to the system DNS.
+
+ \sa QWebEngineGlobalSettings::SecureDnsMode
+*/
+
+/*!
+ \variable QWebEngineGlobalSettings::DnsMode::serverTemplates
+ \brief A list of server URI templates used for secure DNS-over-HTTPS host resolution.
+
+ The \c serverTemplates structure member lists
+ \l{https://datatracker.ietf.org/d7oc/html/rfc6570}{URI templates}.
+ An example of a URI template is https://dns.google/dns-query{?dns}.
+*/
+
+/*!
+ \fn void QWebEngineGlobalSettings::setDnsMode(DnsMode dnsMode)
+
+ Sets \a dnsMode for DNS-over-HTTPS host resolution.
+
+ This function returns \c false if the \l {QWebEngineGlobalSettings::DnsMode::serverTemplates}
+ {serverTemplates} list in the \l {QWebEngineGlobalSettings::DnsMode}{DnsMode} structure is empty
+ or contains URI templates that cannot be parsed for SecureDnsMode::SecureOnly or
+ SecureDnsMode::SecureWithFallback. Otherwise, it returns \c true meaning that the DNS mode
+ change is triggered.
+*/
+
+bool QWebEngineGlobalSettings::setDnsMode(DnsMode dnsMode)
+{
+ QWebEngineGlobalSettingsPrivate *d = QWebEngineGlobalSettingsPrivate::instance();
+ if (dnsMode.secureMode != SecureDnsMode::SystemOnly) {
+ const QString servers = dnsMode.serverTemplates.join(QChar::Space);
+ const std::string templates = servers.toStdString();
+ if (!QtWebEngineCore::isValidTemplates(templates))
+ return false;
+ d->dnsOverHttpsTemplates = templates;
+ }
+ d->dnsMode = dnsMode.secureMode;
+ d->configureStubHostResolver();
+ return true;
+}
+
+/*!
+ \internal
+*/
+QWebEngineGlobalSettingsPrivate *QWebEngineGlobalSettingsPrivate::instance()
+{
+ static QWebEngineGlobalSettingsPrivate settings;
+ return &settings;
+}
+
+void QWebEngineGlobalSettingsPrivate::configureStubHostResolver()
+{
+ QtWebEngineCore::configureStubHostResolver(dnsMode, dnsOverHttpsTemplates, insecureDnsClientEnabled, additionalInsecureDnsTypesEnabled);
+}
+
+QT_END_NAMESPACE
diff --git a/src/core/api/qwebengineglobalsettings.h b/src/core/api/qwebengineglobalsettings.h
new file mode 100644
index 000000000..a9eff6d12
--- /dev/null
+++ b/src/core/api/qwebengineglobalsettings.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINEGLOBALSETTINGS_H
+#define QWEBENGINEGLOBALSETTINGS_H
+
+#if 0
+#pragma qt_class(QWebEngineGlobalSettings)
+#endif
+
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+#include <QtCore/QObject>
+#include <QtCore/QScopedPointer>
+
+QT_BEGIN_NAMESPACE
+
+namespace QWebEngineGlobalSettings {
+// Mapping net::SecureDnsMode
+enum class SecureDnsMode : quint8 { SystemOnly = 0, SecureWithFallback = 1, SecureOnly = 2 };
+struct DnsMode
+{
+ SecureDnsMode secureMode = SecureDnsMode::SystemOnly;
+ QStringList serverTemplates;
+};
+Q_WEBENGINECORE_EXPORT bool setDnsMode(DnsMode dnsMode);
+}
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEGLOBALSETTINGS_H
diff --git a/src/core/api/qwebengineglobalsettings_p.h b/src/core/api/qwebengineglobalsettings_p.h
new file mode 100644
index 000000000..8e35ad68c
--- /dev/null
+++ b/src/core/api/qwebengineglobalsettings_p.h
@@ -0,0 +1,44 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINEGLOBALSETTINGS_P_H
+#define QWEBENGINEGLOBALSETTINGS_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 "qtwebenginecoreglobal_p.h"
+#include "qwebengineglobalsettings.h"
+#include <string>
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBENGINECORE_EXPORT QWebEngineGlobalSettingsPrivate
+{
+public:
+ QWebEngineGlobalSettingsPrivate()
+ : dnsMode(QWebEngineGlobalSettings::SecureDnsMode::SystemOnly)
+ , dnsOverHttpsTemplates("")
+ , insecureDnsClientEnabled(false)
+ , additionalInsecureDnsTypesEnabled(false){};
+
+ static QWebEngineGlobalSettingsPrivate *instance();
+ QWebEngineGlobalSettings::SecureDnsMode dnsMode;
+ std::string dnsOverHttpsTemplates;
+ const bool insecureDnsClientEnabled;
+ const bool additionalInsecureDnsTypesEnabled;
+
+ void configureStubHostResolver();
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEGLOBALSETTINGS_P_H
diff --git a/src/core/api/qwebenginehistory.cpp b/src/core/api/qwebenginehistory.cpp
index b70c0b73d..5d2fc8e9e 100644
--- a/src/core/api/qwebenginehistory.cpp
+++ b/src/core/api/qwebenginehistory.cpp
@@ -242,13 +242,6 @@ QWebEngineHistory::QWebEngineHistory(QWebEngineHistoryPrivate *d) : d_ptr(d) { }
QWebEngineHistory::~QWebEngineHistory() { }
-/*!
- \qmlmethod void WebEngineHistory::clear()
- \since QtWebEngine 1.11
-
- Clears the history.
-*/
-
void QWebEngineHistory::clear()
{
Q_D(const QWebEngineHistory);
diff --git a/src/core/api/qwebenginehistory_p.h b/src/core/api/qwebenginehistory_p.h
index 99c42d7eb..fe28f4a0e 100644
--- a/src/core/api/qwebenginehistory_p.h
+++ b/src/core/api/qwebenginehistory_p.h
@@ -72,7 +72,7 @@ public:
int offsetForIndex(int) const override;
};
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineHistoryPrivate
+class Q_WEBENGINECORE_EXPORT QWebEngineHistoryPrivate
{
public:
typedef std::function<QUrl (const QUrl &)> ImageProviderUrl;
diff --git a/src/core/api/qwebengineloadinginfo.cpp b/src/core/api/qwebengineloadinginfo.cpp
index 14ec26be4..a72117e9d 100644
--- a/src/core/api/qwebengineloadinginfo.cpp
+++ b/src/core/api/qwebengineloadinginfo.cpp
@@ -22,13 +22,15 @@ Q_STATIC_ASSERT(static_cast<int>(WebEngineError::HttpStatusCodeDomain) == static
class QWebEngineLoadingInfo::QWebEngineLoadingInfoPrivate : public QSharedData {
public:
QWebEngineLoadingInfoPrivate(const QUrl& url, LoadStatus status, bool isErrorPage,
- const QString& errorString, int errorCode, ErrorDomain errorDomain)
+ const QString& errorString, int errorCode, ErrorDomain errorDomain,
+ const QMultiMap<QByteArray,QByteArray>& responseHeaders)
: url(url)
, status(status)
, isErrorPage(isErrorPage)
, errorString(errorString)
, errorCode(errorCode)
, errorDomain(errorDomain)
+ , responseHeaders(responseHeaders)
{
}
@@ -38,6 +40,7 @@ public:
QString errorString;
int errorCode;
ErrorDomain errorDomain;
+ QMultiMap<QByteArray,QByteArray> responseHeaders;
};
/*!
@@ -52,8 +55,10 @@ public:
\sa QWebEnginePage::loadStarted, QWebEnginePage::loadFinished, WebEngineView::loadingChanged
*/
QWebEngineLoadingInfo::QWebEngineLoadingInfo(const QUrl& url, LoadStatus status, bool isErrorPage,
- const QString& errorString, int errorCode, ErrorDomain errorDomain)
- : d_ptr(new QWebEngineLoadingInfoPrivate(url, status, isErrorPage, errorString, errorCode, errorDomain))
+ const QString& errorString, int errorCode, ErrorDomain errorDomain,
+ const QMultiMap<QByteArray,QByteArray>& responseHeaders)
+ : d_ptr(new QWebEngineLoadingInfoPrivate(url, status, isErrorPage, errorString, errorCode, errorDomain,
+ responseHeaders))
{
}
@@ -157,6 +162,19 @@ int QWebEngineLoadingInfo::errorCode() const
return d->errorCode;
}
+/*!
+ \property QWebEngineLoadingInfo::responseHeaders
+ \since 6.6
+ \brief Holds the response headers when \c QWebEngineLoadingInfo::status()
+ is equal to \c QWebEngineLoadingInfo::LoadSucceededStatus or
+ \c QWebEngineLoadingInfo::LoadFailedStatus.
+*/
+QMultiMap<QByteArray,QByteArray> QWebEngineLoadingInfo::responseHeaders() const
+{
+ Q_D(const QWebEngineLoadingInfo);
+ return d->responseHeaders;
+}
+
QT_END_NAMESPACE
#include "moc_qwebengineloadinginfo.cpp"
diff --git a/src/core/api/qwebengineloadinginfo.h b/src/core/api/qwebengineloadinginfo.h
index a17588a57..48d14601a 100644
--- a/src/core/api/qwebengineloadinginfo.h
+++ b/src/core/api/qwebengineloadinginfo.h
@@ -6,8 +6,9 @@
#include <QtWebEngineCore/qtwebenginecoreglobal.h>
-#include <QtCore/qshareddata.h>
+#include <QtCore/qmap.h>
#include <QtCore/qobject.h>
+#include <QtCore/qshareddata.h>
#include <QtCore/qurl.h>
namespace QtWebEngineCore {
@@ -26,6 +27,7 @@ class Q_WEBENGINECORE_EXPORT QWebEngineLoadingInfo
Q_PROPERTY(QString errorString READ errorString CONSTANT FINAL)
Q_PROPERTY(ErrorDomain errorDomain READ errorDomain CONSTANT FINAL)
Q_PROPERTY(int errorCode READ errorCode CONSTANT FINAL)
+ Q_PROPERTY(QMultiMap<QByteArray,QByteArray> responseHeaders READ responseHeaders CONSTANT REVISION(6,6) FINAL)
public:
enum LoadStatus {
@@ -60,11 +62,13 @@ public:
QString errorString() const;
ErrorDomain errorDomain() const;
int errorCode() const;
+ QMultiMap<QByteArray,QByteArray> responseHeaders() const;
private:
QWebEngineLoadingInfo(const QUrl &url, LoadStatus status, bool isErrorPage = false,
const QString &errorString = QString(), int errorCode = 0,
- ErrorDomain errorDomain = NoErrorDomain);
+ ErrorDomain errorDomain = NoErrorDomain,
+ const QMultiMap<QByteArray,QByteArray> &responseHeaders = {});
class QWebEngineLoadingInfoPrivate;
Q_DECLARE_PRIVATE(QWebEngineLoadingInfo)
QExplicitlySharedDataPointer<QWebEngineLoadingInfoPrivate> d_ptr;
diff --git a/src/core/api/qwebenginemessagepumpscheduler.cpp b/src/core/api/qwebenginemessagepumpscheduler.cpp
index 62244c787..a435e2c0c 100644
--- a/src/core/api/qwebenginemessagepumpscheduler.cpp
+++ b/src/core/api/qwebenginemessagepumpscheduler.cpp
@@ -11,9 +11,14 @@ QWebEngineMessagePumpScheduler::QWebEngineMessagePumpScheduler(std::function<voi
: m_callback(std::move(callback))
{}
-void QWebEngineMessagePumpScheduler::scheduleWork()
+void QWebEngineMessagePumpScheduler::scheduleImmediateWork()
{
- QCoreApplication::postEvent(this, new QTimerEvent(0));
+ QCoreApplication::postEvent(this, new QTimerEvent(0), Qt::NormalEventPriority);
+}
+
+void QWebEngineMessagePumpScheduler::scheduleIdleWork()
+{
+ QCoreApplication::postEvent(this, new QTimerEvent(0), Qt::LowEventPriority);
}
void QWebEngineMessagePumpScheduler::scheduleDelayedWork(int delay)
diff --git a/src/core/api/qwebenginemessagepumpscheduler_p.h b/src/core/api/qwebenginemessagepumpscheduler_p.h
index 7e84b4190..37f7dd9a6 100644
--- a/src/core/api/qwebenginemessagepumpscheduler_p.h
+++ b/src/core/api/qwebenginemessagepumpscheduler_p.h
@@ -23,12 +23,13 @@
QT_BEGIN_NAMESPACE
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineMessagePumpScheduler : public QObject
+class Q_WEBENGINECORE_EXPORT QWebEngineMessagePumpScheduler : public QObject
{
Q_OBJECT
public:
QWebEngineMessagePumpScheduler(std::function<void()> callback);
- void scheduleWork();
+ void scheduleImmediateWork();
+ void scheduleIdleWork();
void scheduleDelayedWork(int delay);
protected:
diff --git a/src/core/api/qwebenginenavigationrequest.cpp b/src/core/api/qwebenginenavigationrequest.cpp
index c14a7bf41..0a30f6472 100644
--- a/src/core/api/qwebenginenavigationrequest.cpp
+++ b/src/core/api/qwebenginenavigationrequest.cpp
@@ -89,7 +89,10 @@ void QWebEngineNavigationRequest::setAction(QWebEngineNavigationRequest::Navigat
return;
acceptRequest ? accept() : reject();
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
emit actionChanged();
+QT_WARNING_POP
}
#endif
/*!
diff --git a/src/core/api/qwebenginepage.cpp b/src/core/api/qwebenginepage.cpp
index ac44fad10..ac645c430 100644
--- a/src/core/api/qwebenginepage.cpp
+++ b/src/core/api/qwebenginepage.cpp
@@ -2,9 +2,11 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qwebenginepage.h"
+#include "authenticator_request_dialog_controller.h"
#include "qwebenginepage_p.h"
#include "qwebenginecertificateerror.h"
+#include "qwebenginedesktopmediarequest.h"
#include "qwebenginefilesystemaccessrequest.h"
#include "qwebenginefindtextresult.h"
#include "qwebenginefullscreenrequest.h"
@@ -21,6 +23,7 @@
#include "qwebenginescript.h"
#include "qwebenginescriptcollection_p.h"
#include "qwebenginesettings.h"
+#include "qwebenginewebauthuxrequest.h"
#include "authentication_dialog_controller.h"
#include "autofill_popup_controller.h"
@@ -42,8 +45,10 @@
#include <QClipboard>
#include <QKeyEvent>
#include <QIcon>
+
#include <QLoggingCategory>
#include <QMimeData>
+#include <QtCore/QPointer>
#include <QRect>
#include <QTimer>
#include <QUrl>
@@ -103,7 +108,9 @@ QWebEnginePagePrivate::QWebEnginePagePrivate(QWebEngineProfile *_profile)
{
memset(actions, 0, sizeof(actions));
+#if QT_DEPRECATED_SINCE(6, 5)
qRegisterMetaType<QWebEngineQuotaRequest>();
+#endif
qRegisterMetaType<QWebEngineRegisterProtocolHandlerRequest>();
qRegisterMetaType<QWebEngineFileSystemAccessRequest>();
qRegisterMetaType<QWebEngineFindTextResult>();
@@ -329,6 +336,109 @@ void QWebEnginePagePrivate::createNewWindow(WindowOpenDisposition disposition, b
Q_EMIT q->newWindowRequested(request);
}
+QString QWebEnginePagePrivate::actionText(int action)
+{
+ switch (action) {
+ case QWebEnginePage::Back:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Back);
+ case QWebEnginePage::Forward:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Forward);
+ case QWebEnginePage::Stop:
+ return QWebEnginePage::tr("Stop");
+ case QWebEnginePage::Reload:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Reload);
+ case QWebEnginePage::ReloadAndBypassCache:
+ return QWebEnginePage::tr("Reload and Bypass Cache");
+ case QWebEnginePage::Cut:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Cut);
+ case QWebEnginePage::Copy:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Copy);
+ case QWebEnginePage::Paste:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Paste);
+ case QWebEnginePage::Undo:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Undo);
+ case QWebEnginePage::Redo:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Redo);
+ case QWebEnginePage::SelectAll:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SelectAll);
+ case QWebEnginePage::PasteAndMatchStyle:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::PasteAndMatchStyle);
+ case QWebEnginePage::OpenLinkInThisWindow:
+ return QWebEnginePage::tr("Open link in this window");
+ case QWebEnginePage::OpenLinkInNewWindow:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewWindow);
+ case QWebEnginePage::OpenLinkInNewTab:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewTab);
+ case QWebEnginePage::OpenLinkInNewBackgroundTab:
+ return QWebEnginePage::tr("Open link in new background tab");
+ case QWebEnginePage::CopyLinkToClipboard:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyLinkToClipboard);
+ case QWebEnginePage::DownloadLinkToDisk:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadLinkToDisk);
+ case QWebEnginePage::CopyImageToClipboard:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageToClipboard);
+ case QWebEnginePage::CopyImageUrlToClipboard:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageUrlToClipboard);
+ case QWebEnginePage::DownloadImageToDisk:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadImageToDisk);
+ case QWebEnginePage::CopyMediaUrlToClipboard:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyMediaUrlToClipboard);
+ case QWebEnginePage::ToggleMediaControls:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaControls);
+ case QWebEnginePage::ToggleMediaLoop:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaLoop);
+ case QWebEnginePage::ToggleMediaPlayPause:
+ return QWebEnginePage::tr("Toggle Play/Pause");
+ case QWebEnginePage::ToggleMediaMute:
+ return QWebEnginePage::tr("Toggle Mute");
+ case QWebEnginePage::DownloadMediaToDisk:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadMediaToDisk);
+ case QWebEnginePage::InspectElement:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::InspectElement);
+ case QWebEnginePage::ExitFullScreen:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ExitFullScreen);
+ case QWebEnginePage::RequestClose:
+ return QWebEnginePage::tr("Close Page");
+ case QWebEnginePage::Unselect:
+ return QWebEnginePage::tr("Unselect");
+ case QWebEnginePage::SavePage:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SavePage);
+ case QWebEnginePage::ViewSource:
+ return RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ViewSource);
+ case QWebEnginePage::ToggleBold:
+ return QWebEnginePage::tr("&Bold");
+ case QWebEnginePage::ToggleItalic:
+ return QWebEnginePage::tr("&Italic");
+ case QWebEnginePage::ToggleUnderline:
+ return QWebEnginePage::tr("&Underline");
+ case QWebEnginePage::ToggleStrikethrough:
+ return QWebEnginePage::tr("&Strikethrough");
+ case QWebEnginePage::AlignLeft:
+ return QWebEnginePage::tr("Align &Left");
+ case QWebEnginePage::AlignCenter:
+ return QWebEnginePage::tr("Align &Center");
+ case QWebEnginePage::AlignRight:
+ return QWebEnginePage::tr("Align &Right");
+ case QWebEnginePage::AlignJustified:
+ return QWebEnginePage::tr("Align &Justified");
+ case QWebEnginePage::Indent:
+ return QWebEnginePage::tr("&Indent");
+ case QWebEnginePage::Outdent:
+ return QWebEnginePage::tr("&Outdent");
+ case QWebEnginePage::InsertOrderedList:
+ return QWebEnginePage::tr("Insert &Ordered List");
+ case QWebEnginePage::InsertUnorderedList:
+ return QWebEnginePage::tr("Insert &Unordered List");
+ case QWebEnginePage::ChangeTextDirectionLTR:
+ return QWebEnginePage::tr("Change text direction left to right");
+ case QWebEnginePage::ChangeTextDirectionRTL:
+ return QWebEnginePage::tr("Change text direction right to left");
+ default:
+ break;
+ }
+ return {};
+}
+
class WebContentsAdapterOwner : public QObject
{
public:
@@ -351,6 +461,8 @@ bool QWebEnginePagePrivate::adoptWebContents(WebContentsAdapter *webContents)
m_isBeingAdopted = true;
+ webContents->setRequestInterceptor(adapter->requestInterceptor());
+
// This throws away the WebContentsAdapter that has been used until now.
// All its states, particularly the loading URL, are replaced by the adopted WebContentsAdapter.
WebContentsAdapterOwner *adapterOwner = new WebContentsAdapterOwner(adapter->sharedFromThis());
@@ -483,6 +595,10 @@ static QWebEnginePage::Feature toFeature(QtWebEngineCore::ProfileAdapter::Permis
return QWebEnginePage::Notifications;
case QtWebEngineCore::ProfileAdapter::GeolocationPermission:
return QWebEnginePage::Geolocation;
+ case QtWebEngineCore::ProfileAdapter::ClipboardReadWrite:
+ return QWebEnginePage::ClipboardReadWrite;
+ case QtWebEngineCore::ProfileAdapter::LocalFontsPermission:
+ return QWebEnginePage::LocalFontsAccess;
default:
break;
}
@@ -508,6 +624,15 @@ void QWebEnginePagePrivate::runRegisterProtocolHandlerRequest(QWebEngineRegister
Q_EMIT q->registerProtocolHandlerRequested(request);
}
+/*!
+ \fn void QWebEnginePage::fileSystemAccessRequested(QWebEngineFileSystemAccessRequest request)
+ \since 6.4
+
+ This signal is emitted when the web page requests access to local files or directories.
+
+ The request object \a request can be used to accept or reject the request.
+*/
+
void QWebEnginePagePrivate::runFileSystemAccessRequest(QWebEngineFileSystemAccessRequest request)
{
Q_Q(QWebEnginePage);
@@ -673,6 +798,12 @@ void QWebEnginePagePrivate::ensureInitialized() const
adapter->loadDefault();
}
+void QWebEnginePagePrivate::showWebAuthDialog(QWebEngineWebAuthUxRequest *request)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->webAuthUxRequested(request);
+}
+
QWebEnginePage::QWebEnginePage(QObject* parent)
: QObject(parent)
, d_ptr(new QWebEnginePagePrivate())
@@ -1042,148 +1173,7 @@ QAction *QWebEnginePage::action(WebAction action) const
if (d->actions[action])
return d->actions[action];
- QString text;
- switch (action) {
- case Back:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Back);
- break;
- case Forward:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Forward);
- break;
- case Stop:
- text = tr("Stop");
- break;
- case Reload:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Reload);
- break;
- case ReloadAndBypassCache:
- text = tr("Reload and Bypass Cache");
- break;
- case Cut:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Cut);
- break;
- case Copy:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Copy);
- break;
- case Paste:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Paste);
- break;
- case Undo:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Undo);
- break;
- case Redo:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Redo);
- break;
- case SelectAll:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SelectAll);
- break;
- case PasteAndMatchStyle:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::PasteAndMatchStyle);
- break;
- case OpenLinkInThisWindow:
- text = tr("Open link in this window");
- break;
- case OpenLinkInNewWindow:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewWindow);
- break;
- case OpenLinkInNewTab:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewTab);
- break;
- case OpenLinkInNewBackgroundTab:
- text = tr("Open link in new background tab");
- break;
- case CopyLinkToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyLinkToClipboard);
- break;
- case DownloadLinkToDisk:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadLinkToDisk);
- break;
- case CopyImageToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageToClipboard);
- break;
- case CopyImageUrlToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageUrlToClipboard);
- break;
- case DownloadImageToDisk:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadImageToDisk);
- break;
- case CopyMediaUrlToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyMediaUrlToClipboard);
- break;
- case ToggleMediaControls:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaControls);
- break;
- case ToggleMediaLoop:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaLoop);
- break;
- case ToggleMediaPlayPause:
- text = tr("Toggle Play/Pause");
- break;
- case ToggleMediaMute:
- text = tr("Toggle Mute");
- break;
- case DownloadMediaToDisk:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadMediaToDisk);
- break;
- case InspectElement:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::InspectElement);
- break;
- case ExitFullScreen:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ExitFullScreen);
- break;
- case RequestClose:
- text = tr("Close Page");
- break;
- case Unselect:
- text = tr("Unselect");
- break;
- case SavePage:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SavePage);
- break;
- case ViewSource:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ViewSource);
- break;
- case ToggleBold:
- text = tr("&Bold");
- break;
- case ToggleItalic:
- text = tr("&Italic");
- break;
- case ToggleUnderline:
- text = tr("&Underline");
- break;
- case ToggleStrikethrough:
- text = tr("&Strikethrough");
- break;
- case AlignLeft:
- text = tr("Align &Left");
- break;
- case AlignCenter:
- text = tr("Align &Center");
- break;
- case AlignRight:
- text = tr("Align &Right");
- break;
- case AlignJustified:
- text = tr("Align &Justified");
- break;
- case Indent:
- text = tr("&Indent");
- break;
- case Outdent:
- text = tr("&Outdent");
- break;
- case InsertOrderedList:
- text = tr("Insert &Ordered List");
- break;
- case InsertUnorderedList:
- text = tr("Insert &Unordered List");
- break;
- case NoWebAction:
- case WebActionCount:
- Q_UNREACHABLE();
- break;
- }
+ const QString text = QWebEnginePagePrivate::actionText(action);
QAction *a = new QAction(const_cast<QWebEnginePage*>(this));
a->setText(text);
@@ -1452,6 +1442,12 @@ void QWebEnginePage::triggerAction(WebAction action, bool)
case InsertUnorderedList:
runJavaScript(QStringLiteral("document.execCommand('insertUnorderedList');"), QWebEngineScript::ApplicationWorld);
break;
+ case ChangeTextDirectionLTR:
+ d->adapter->changeTextDirection(true /*left to right*/);
+ break;
+ case ChangeTextDirectionRTL:
+ d->adapter->changeTextDirection(false /*left to right*/);
+ break;
case NoWebAction:
break;
case WebActionCount:
@@ -1495,6 +1491,15 @@ bool QWebEnginePage::event(QEvent *e)
return QObject::event(e);
}
+void QWebEnginePagePrivate::desktopMediaRequested(
+ QtWebEngineCore::DesktopMediaController *controller)
+{
+ Q_Q(QWebEnginePage);
+ QTimer::singleShot(0, q, [q, controller]() {
+ Q_EMIT q->desktopMediaRequested(QWebEngineDesktopMediaRequest(controller));
+ });
+}
+
void QWebEnginePagePrivate::contextMenuRequested(QWebEngineContextMenuRequest *data)
{
if (view)
@@ -1502,7 +1507,7 @@ void QWebEnginePagePrivate::contextMenuRequested(QWebEngineContextMenuRequest *d
}
/*!
- \fn bool QWebEnginePage::navigationRequested(QWebEngineNavigationRequest &request)
+ \fn void QWebEnginePage::navigationRequested(QWebEngineNavigationRequest &request)
\since 6.2
This signal is emitted on navigation together with the call the acceptNavigationRequest().
@@ -1643,6 +1648,17 @@ void QWebEnginePagePrivate::setToolTip(const QString &toolTipText)
view->setToolTip(toolTipText);
}
+/*!
+ \fn void QWebEnginePage::printRequested()
+ \since 5.12
+
+ This signal is emitted when the JavaScript \c{window.print()} method is called or the user pressed the print
+ button of PDF viewer plugin.
+ Typically, the signal handler can simply call printToPdf().
+
+ \sa printToPdf()
+*/
+
void QWebEnginePagePrivate::printRequested()
{
Q_Q(QWebEnginePage);
@@ -1705,7 +1721,9 @@ void QWebEnginePagePrivate::visibleChanged(bool visible)
The page does not take ownership of the pointer. This interceptor is called
after any interceptors on the profile, and unlike profile interceptors, only
- URL requests from this page are intercepted.
+ URL requests from this page are intercepted. If the original request was
+ already blocked or redirected by the profile interceptor, it will not be
+ intercepted by this.
To unset the request interceptor, set a \c nullptr.
@@ -1736,6 +1754,13 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine
case Notifications:
d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AskPermission);
break;
+ case ClipboardReadWrite:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite,
+ ProfileAdapter::AskPermission);
+ break;
+ case LocalFontsAccess:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, ProfileAdapter::AskPermission);
+ break;
}
return;
}
@@ -1773,6 +1798,13 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine
case Notifications:
d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::AllowedPermission);
break;
+ case ClipboardReadWrite:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite,
+ ProfileAdapter::AllowedPermission);
+ break;
+ case LocalFontsAccess:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, ProfileAdapter::AllowedPermission);
+ break;
}
} else { // if (policy == PermissionDeniedByUser)
switch (feature) {
@@ -1792,6 +1824,13 @@ void QWebEnginePage::setFeaturePermission(const QUrl &securityOrigin, QWebEngine
case Notifications:
d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission, ProfileAdapter::DeniedPermission);
break;
+ case ClipboardReadWrite:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite,
+ ProfileAdapter::DeniedPermission);
+ break;
+ case LocalFontsAccess:
+ d->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission, ProfileAdapter::DeniedPermission);
+ break;
}
}
}
@@ -1999,7 +2038,10 @@ void QWebEnginePage::runJavaScript(const QString& scriptSource, const std::funct
return;
}
quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, QWebEngineScript::MainWorld);
- d->m_variantCallbacks.insert(requestId, resultCallback);
+ if (requestId)
+ d->m_variantCallbacks.insert(requestId, resultCallback);
+ else if (resultCallback)
+ resultCallback(QVariant());
}
void QWebEnginePage::runJavaScript(const QString& scriptSource, quint32 worldId, const std::function<void(const QVariant &)> &resultCallback)
@@ -2014,7 +2056,10 @@ void QWebEnginePage::runJavaScript(const QString& scriptSource, quint32 worldId,
}
if (resultCallback) {
quint64 requestId = d->adapter->runJavaScriptCallbackResult(scriptSource, worldId);
- d->m_variantCallbacks.insert(requestId, resultCallback);
+ if (requestId)
+ d->m_variantCallbacks.insert(requestId, resultCallback);
+ else
+ resultCallback(QVariant());
} else {
d->adapter->runJavaScript(scriptSource, worldId);
}
@@ -2130,6 +2175,24 @@ void QWebEnginePage::setDevToolsPage(QWebEnginePage *devToolsPage)
}
}
+/*!
+ \since 6.6
+ Returns the id of the developer tools host associated with this page.
+
+ If remote debugging is enabled (see \l{Qt WebEngine Developer Tools}), the id can be used to
+ build the URL to connect to the developer tool websocket:
+ \c{ws://localhost:<debugggin-port>/devtools/page/<id>)}. The websocket can be used to to interact
+ with the page using the \l{https://chromedevtools.github.io/devtools-protocol/}{DevTools
+ Protocol}.
+*/
+
+QString QWebEnginePage::devToolsId() const
+{
+ Q_D(const QWebEnginePage);
+ d->ensureInitialized();
+ return d->adapter->devToolsId();
+}
+
ASSERT_ENUMS_MATCH(FilePickerController::Open, QWebEnginePage::FileSelectOpen)
ASSERT_ENUMS_MATCH(FilePickerController::OpenMultiple, QWebEnginePage::FileSelectOpenMultiple)
ASSERT_ENUMS_MATCH(FilePickerController::UploadFolder, QWebEnginePage::FileSelectUploadFolder)
@@ -2248,6 +2311,9 @@ QSizeF QWebEnginePage::contentsSize() const
To be informed about the result of the request, connect to the signal
pdfPrintingFinished().
+ \note The \l QWebEnginePage::Stop web action can be used to interrupt
+ this asynchronous operation.
+
If a file already exists at the provided file path, it will be overwritten.
\sa pdfPrintingFinished()
*/
@@ -2273,6 +2339,8 @@ void QWebEnginePage::printToPdf(const QString &filePath, const QPageLayout &layo
The \a resultCallback must take a const reference to a QByteArray as parameter. If printing was successful, this byte array
will contain the PDF data, otherwise, the byte array will be empty.
+ \note The \l QWebEnginePage::Stop web action can be used to interrupt this operation.
+
\warning We guarantee that the callback (\a resultCallback) is always called, but it might be done
during page destruction. When QWebEnginePage is deleted, the callback is triggered with an invalid
value and it is not safe to use the corresponding QWebEnginePage or QWebEngineView instance inside it.
diff --git a/src/core/api/qwebenginepage.h b/src/core/api/qwebenginepage.h
index c60feb3ab..c857585ab 100644
--- a/src/core/api/qwebenginepage.h
+++ b/src/core/api/qwebenginepage.h
@@ -26,6 +26,7 @@ class QRect;
class QVariant;
class QWebChannel;
class QWebEngineCertificateError;
+class QWebEngineDesktopMediaRequest;
class QWebEngineFileSystemAccessRequest;
class QWebEngineFindTextResult;
class QWebEngineFullScreenRequest;
@@ -40,6 +41,7 @@ class QWebEngineRegisterProtocolHandlerRequest;
class QWebEngineScriptCollection;
class QWebEngineSettings;
class QWebEngineUrlRequestInterceptor;
+class QWebEngineWebAuthUxRequest;
class Q_WEBENGINECORE_EXPORT QWebEnginePage : public QObject
{
@@ -48,8 +50,8 @@ class Q_WEBENGINECORE_EXPORT QWebEnginePage : public QObject
Q_PROPERTY(bool hasSelection READ hasSelection)
Q_PROPERTY(QUrl requestedUrl READ requestedUrl)
Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor)
- Q_PROPERTY(QString title READ title)
- Q_PROPERTY(QUrl url READ url WRITE setUrl)
+ Q_PROPERTY(QString title READ title NOTIFY titleChanged)
+ Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged)
Q_PROPERTY(QUrl iconUrl READ iconUrl NOTIFY iconUrlChanged)
Q_PROPERTY(QIcon icon READ icon NOTIFY iconChanged)
Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
@@ -122,6 +124,9 @@ public:
InsertOrderedList,
InsertUnorderedList,
+ ChangeTextDirectionLTR,
+ ChangeTextDirectionRTL,
+
WebActionCount
};
Q_ENUM(WebAction)
@@ -167,7 +172,9 @@ public:
MediaAudioVideoCapture,
MouseLock,
DesktopVideoCapture,
- DesktopAudioVideoCapture
+ DesktopAudioVideoCapture,
+ ClipboardReadWrite,
+ LocalFontsAccess,
};
Q_ENUM(Feature)
@@ -282,6 +289,7 @@ public:
QWebEnginePage *inspectedPage() const;
void setDevToolsPage(QWebEnginePage *page);
QWebEnginePage *devToolsPage() const;
+ QString devToolsId() const;
void setUrlRequestInterceptor(QWebEngineUrlRequestInterceptor *interceptor);
@@ -320,6 +328,7 @@ Q_SIGNALS:
void proxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *authenticator, const QString &proxyHost);
void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode);
+ void desktopMediaRequested(const QWebEngineDesktopMediaRequest &request);
void certificateError(const QWebEngineCertificateError &certificateError);
void navigationRequested(QWebEngineNavigationRequest &request);
void newWindowRequested(QWebEngineNewWindowRequest &request);
@@ -349,6 +358,8 @@ Q_SIGNALS:
// TODO: fixme / rewrite bindPageToView
void _q_aboutToDelete();
+ void webAuthUxRequested(QWebEngineWebAuthUxRequest *request);
+
protected:
virtual QWebEnginePage *createWindow(WebWindowType type);
virtual QStringList chooseFiles(FileSelectionMode mode, const QStringList &oldFiles,
diff --git a/src/core/api/qwebenginepage_p.h b/src/core/api/qwebenginepage_p.h
index bb33c7e98..a51d8603b 100644
--- a/src/core/api/qwebenginepage_p.h
+++ b/src/core/api/qwebenginepage_p.h
@@ -84,7 +84,7 @@ public:
virtual void hideTouchSelectionMenu() = 0;
};
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient
+class Q_WEBENGINECORE_EXPORT QWebEnginePagePrivate : public QtWebEngineCore::WebContentsAdapterClient
{
public:
Q_DECLARE_PUBLIC(QWebEnginePage)
@@ -122,6 +122,7 @@ public:
bool isBeingAdopted() override;
void close() override;
void windowCloseRejected() override;
+ void desktopMediaRequested(QtWebEngineCore::DesktopMediaController *) override;
void contextMenuRequested(QWebEngineContextMenuRequest *request) override;
void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame) override;
void requestFullScreenMode(const QUrl &origin, bool fullscreen) override;
@@ -171,6 +172,7 @@ public:
void showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller,
const QRect &bounds, bool autoselectFirstSuggestion) override;
void hideAutofillPopup() override;
+ void showWebAuthDialog(QWebEngineWebAuthUxRequest *controller) override;
QtWebEngineCore::ProfileAdapter *profileAdapter() override;
QtWebEngineCore::WebContentsAdapter *webContentsAdapter() override;
@@ -186,6 +188,8 @@ public:
void setFullScreenMode(bool);
void ensureInitialized() const;
+ static QString actionText(int action);
+
QSharedPointer<QtWebEngineCore::WebContentsAdapter> adapter;
QWebEngineHistory *history;
QWebEngineProfile *profile;
diff --git a/src/core/api/qwebengineprofile.cpp b/src/core/api/qwebengineprofile.cpp
index fe783b75e..dbb98102c 100644
--- a/src/core/api/qwebengineprofile.cpp
+++ b/src/core/api/qwebengineprofile.cpp
@@ -3,6 +3,7 @@
#include "qwebengineprofile.h"
#include "qwebengineprofile_p.h"
+#include "qwebengineclienthints.h"
#include "qwebenginecookiestore.h"
#include "qwebenginedownloadrequest.h"
#include "qwebenginedownloadrequest_p.h"
@@ -128,11 +129,22 @@ void QWebEngineProfilePrivate::showNotification(QSharedPointer<QtWebEngineCore::
\sa QWebEngineDownloadRequest, QWebEnginePage::download()
*/
+/*!
+ \fn QWebEngineProfile::clearHttpCacheCompleted()
+
+ \since 6.7
+
+ This signal is emitted when the clearHttpCache() operation is completed.
+
+ \sa QWebEngineProfile::clearHttpCache()
+*/
+
QWebEngineProfilePrivate::QWebEngineProfilePrivate(ProfileAdapter* profileAdapter)
: m_settings(new QWebEngineSettings())
, m_profileAdapter(profileAdapter)
, m_scriptCollection(new QWebEngineScriptCollection(
new QWebEngineScriptCollectionPrivate(profileAdapter->userResourceController())))
+ , m_clientHints(new QWebEngineClientHints(profileAdapter))
{
m_profileAdapter->addClient(this);
}
@@ -186,11 +198,14 @@ void QWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
Q_Q(QWebEngineProfile);
Q_ASSERT(!m_ongoingDownloads.contains(info.id));
- QWebEngineDownloadRequestPrivate *itemPrivate = new QWebEngineDownloadRequestPrivate(m_profileAdapter, info.url);
+ QWebEngineDownloadRequestPrivate *itemPrivate =
+ new QWebEngineDownloadRequestPrivate(m_profileAdapter);
itemPrivate->downloadId = info.id;
itemPrivate->downloadState = info.accepted ? QWebEngineDownloadRequest::DownloadInProgress
: QWebEngineDownloadRequest::DownloadRequested;
itemPrivate->startTime = info.startTime;
+ itemPrivate->downloadUrl = info.url;
+ itemPrivate->totalBytes = info.totalBytes;
itemPrivate->downloadDirectory = QFileInfo(info.path).path();
itemPrivate->downloadFileName = QFileInfo(info.path).fileName();
itemPrivate->suggestedFileName = info.suggestedFileName;
@@ -238,6 +253,12 @@ void QWebEngineProfilePrivate::downloadUpdated(const DownloadItemInfo &info)
download->d_func()->update(info);
}
+void QWebEngineProfilePrivate::clearHttpCacheCompleted()
+{
+ Q_Q(QWebEngineProfile);
+ Q_EMIT q->clearHttpCacheCompleted();
+}
+
void QWebEngineProfilePrivate::addWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter)
{
Q_ASSERT(m_profileAdapter);
@@ -457,7 +478,7 @@ void QWebEngineProfile::setCachePath(const QString &path)
"Windows NT 6.2" (Windows 8), unless the application does contain a manifest
that declares newer Windows versions as supported.
- \sa setHttpUserAgent()
+ \sa setHttpUserAgent(), {windows_manifest} {Windows Application Manifest}
*/
QString QWebEngineProfile::httpUserAgent() const
{
@@ -492,7 +513,10 @@ QWebEngineProfile::HttpCacheType QWebEngineProfile::httpCacheType() const
/*!
Sets the HTTP cache type to \a httpCacheType.
- \sa httpCacheType(), setCachePath()
+ \note Setting the \a httpCacheType to NoCache on the profile, which has already some cache
+ entries does not trigger the removal of those entries.
+
+ \sa httpCacheType(), setCachePath(), clearHttpCache()
*/
void QWebEngineProfile::setHttpCacheType(QWebEngineProfile::HttpCacheType httpCacheType)
{
@@ -811,6 +835,12 @@ void QWebEngineProfile::removeAllUrlSchemeHandlers()
\since 5.7
Removes the profile's cache entries.
+
+ \note Make sure that you do not start new navigation or any operation on the profile while
+ the clear operation is in progress. The clearHttpCacheCompleted() signal notifies about the
+ completion.
+
+ \sa QWebEngineProfile::clearHttpCacheCompleted()
*/
void QWebEngineProfile::clearHttpCache()
{
@@ -899,6 +929,18 @@ void QWebEngineProfile::requestIconForIconURL(const QUrl &url, int desiredSizeIn
iconAvailableCallback);
}
+/*!
+ Return the Client Hints settings associated with this browsing context.
+
+ \since 6.8
+ \sa QWebEngineClientHints
+*/
+QWebEngineClientHints *QWebEngineProfile::clientHints() const
+{
+ Q_D(const QWebEngineProfile);
+ return d->m_clientHints.data();
+}
+
QT_END_NAMESPACE
#include "moc_qwebengineprofile.cpp"
diff --git a/src/core/api/qwebengineprofile.h b/src/core/api/qwebengineprofile.h
index 9fb4c8e74..a0027cb81 100644
--- a/src/core/api/qwebengineprofile.h
+++ b/src/core/api/qwebengineprofile.h
@@ -17,6 +17,7 @@ QT_BEGIN_NAMESPACE
class QUrl;
class QWebEngineClientCertificateStore;
+class QWebEngineClientHints;
class QWebEngineCookieStore;
class QWebEngineDownloadRequest;
class QWebEngineNotification;
@@ -81,6 +82,7 @@ public:
QWebEngineSettings *settings() const;
QWebEngineScriptCollection *scripts() const;
+ QWebEngineClientHints *clientHints() const;
const QWebEngineUrlSchemeHandler *urlSchemeHandler(const QByteArray &) const;
void installUrlSchemeHandler(const QByteArray &scheme, QWebEngineUrlSchemeHandler *);
@@ -112,6 +114,7 @@ public:
Q_SIGNALS:
void downloadRequested(QWebEngineDownloadRequest *download);
+ void clearHttpCacheCompleted();
private:
Q_DISABLE_COPY(QWebEngineProfile)
diff --git a/src/core/api/qwebengineprofile_p.h b/src/core/api/qwebengineprofile_p.h
index b12f778bc..0ccc27037 100644
--- a/src/core/api/qwebengineprofile_p.h
+++ b/src/core/api/qwebengineprofile_p.h
@@ -31,12 +31,13 @@ class WebEngineSettings;
QT_BEGIN_NAMESPACE
+class QWebEngineClientHints;
class QWebEngineNotification;
class QWebEngineProfile;
class QWebEngineScriptCollection;
class QWebEngineSettings;
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineProfilePrivate : public QtWebEngineCore::ProfileAdapterClient {
+class Q_WEBENGINECORE_EXPORT QWebEngineProfilePrivate : public QtWebEngineCore::ProfileAdapterClient {
public:
Q_DECLARE_PUBLIC(QWebEngineProfile)
QWebEngineProfilePrivate(QtWebEngineCore::ProfileAdapter *profileAdapter);
@@ -54,6 +55,7 @@ public:
void downloadUpdated(const DownloadItemInfo &info) override;
void showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &) override;
+ void clearHttpCacheCompleted() override;
void addWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) override;
void removeWebContentsAdapterClient(QtWebEngineCore::WebContentsAdapterClient *adapter) override;
@@ -63,6 +65,7 @@ private:
QWebEngineSettings *m_settings;
QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter;
QScopedPointer<QWebEngineScriptCollection> m_scriptCollection;
+ QScopedPointer<QWebEngineClientHints> m_clientHints;
QMap<quint32, QPointer<QWebEngineDownloadRequest>> m_ongoingDownloads;
std::function<void(std::unique_ptr<QWebEngineNotification>)> m_notificationPresenter;
};
diff --git a/src/core/api/qwebenginescriptcollection_p.h b/src/core/api/qwebenginescriptcollection_p.h
index d675e128a..67b3aa4a7 100644
--- a/src/core/api/qwebenginescriptcollection_p.h
+++ b/src/core/api/qwebenginescriptcollection_p.h
@@ -27,7 +27,7 @@ class UserResourceControllerHost;
} // namespace
QT_BEGIN_NAMESPACE
-class Q_WEBENGINECORE_PRIVATE_EXPORT QWebEngineScriptCollectionPrivate
+class Q_WEBENGINECORE_EXPORT QWebEngineScriptCollectionPrivate
{
public:
QWebEngineScriptCollectionPrivate(QtWebEngineCore::UserResourceControllerHost *, QSharedPointer<QtWebEngineCore::WebContentsAdapter> = QSharedPointer<QtWebEngineCore::WebContentsAdapter>());
diff --git a/src/core/api/qwebenginesettings.cpp b/src/core/api/qwebenginesettings.cpp
index e9f0eb4db..f19d8efe5 100644
--- a/src/core/api/qwebenginesettings.cpp
+++ b/src/core/api/qwebenginesettings.cpp
@@ -103,4 +103,19 @@ void QWebEngineSettings::setParentSettings(QWebEngineSettings *parentSettings)
d_ptr->setParentSettings(parentSettings->d_ptr.data());
}
+void QWebEngineSettings::setImageAnimationPolicy(QWebEngineSettings::ImageAnimationPolicy policy)
+{
+ d_ptr->setImageAnimationPolicy(policy);
+}
+
+QWebEngineSettings::ImageAnimationPolicy QWebEngineSettings::imageAnimationPolicy() const
+{
+ return d_ptr->imageAnimationPolicy();
+}
+
+void QWebEngineSettings::resetImageAnimationPolicy()
+{
+ d_ptr->setImageAnimationPolicy(QWebEngineSettings::InheritedImageAnimationPolicy);
+}
+
QT_END_NAMESPACE
diff --git a/src/core/api/qwebenginesettings.h b/src/core/api/qwebenginesettings.h
index 09656f670..7f89f1ea6 100644
--- a/src/core/api/qwebenginesettings.h
+++ b/src/core/api/qwebenginesettings.h
@@ -60,6 +60,8 @@ public:
DnsPrefetchEnabled,
PdfViewerEnabled,
NavigateOnDropEnabled,
+ ReadingFromCanvasEnabled,
+ ForceDarkMode,
};
enum FontSize {
@@ -76,6 +78,13 @@ public:
AllowAllUnknownUrlSchemes
};
+ enum ImageAnimationPolicy {
+ InheritedImageAnimationPolicy = 0,
+ AllowImageAnimation,
+ AnimateImageOnce,
+ DisallowImageAnimation
+ };
+
public:
~QWebEngineSettings();
void setFontFamily(FontFamily which, const QString &family);
@@ -97,6 +106,10 @@ public:
void setUnknownUrlSchemePolicy(UnknownUrlSchemePolicy policy);
void resetUnknownUrlSchemePolicy();
+ void setImageAnimationPolicy(ImageAnimationPolicy policy);
+ ImageAnimationPolicy imageAnimationPolicy() const;
+ void resetImageAnimationPolicy();
+
private:
explicit QWebEngineSettings(QWebEngineSettings *parentSettings = nullptr);
void setParentSettings(QWebEngineSettings *parentSettings);
diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp
index 162ae7daf..152cf4dd0 100644
--- a/src/core/api/qwebengineurlrequestinfo.cpp
+++ b/src/core/api/qwebengineurlrequestinfo.cpp
@@ -5,6 +5,7 @@
#include "qwebengineurlrequestinfo_p.h"
#include "web_contents_adapter_client.h"
+#include "net/resource_request_body_qt.h"
#include <memory>
#include <utility>
@@ -79,7 +80,8 @@ ASSERT_ENUMS_MATCH(QtWebEngineCore::WebContentsAdapterClient::RedirectNavigation
QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(
QWebEngineUrlRequestInfo::ResourceType resource,
QWebEngineUrlRequestInfo::NavigationType navigation, const QUrl &u, const QUrl &fpu,
- const QUrl &i, const QByteArray &m, const QHash<QByteArray, QByteArray> &h)
+ const QUrl &i, const QByteArray &m, QtWebEngineCore::ResourceRequestBody *const rb,
+ const QHash<QByteArray, QByteArray> &h)
: resourceType(resource)
, navigationType(navigation)
, shouldBlockRequest(false)
@@ -90,6 +92,7 @@ QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(
, method(m)
, changed(false)
, extraHeaders(h)
+ , resourceRequestBody(rb)
{}
/*!
@@ -240,6 +243,20 @@ QByteArray QWebEngineUrlRequestInfo::requestMethod() const
}
/*!
+ Returns a pointer to a QIODevice that gives access to the request body.
+ The request body can contain data for example when the request is
+ a POST request. If the request body is empty the QIODevice reflects this
+ and does not return any data when performing read operations on it.
+
+ \since 6.7
+*/
+
+QIODevice *QWebEngineUrlRequestInfo::requestBody() const
+{
+ return d_ptr->resourceRequestBody;
+}
+
+/*!
\internal
*/
bool QWebEngineUrlRequestInfo::changed() const
@@ -285,8 +302,6 @@ void QWebEngineUrlRequestInfo::block(bool shouldBlock)
void QWebEngineUrlRequestInfo::setHttpHeader(const QByteArray &name, const QByteArray &value)
{
- d_ptr->changed = true;
-
// Headers are case insentive, so we need to compare manually
for (auto it = d_ptr->extraHeaders.begin(); it != d_ptr->extraHeaders.end(); ++it) {
if (it.key().compare(name, Qt::CaseInsensitive) == 0) {
@@ -310,4 +325,13 @@ QHash<QByteArray, QByteArray> QWebEngineUrlRequestInfo::httpHeaders() const
return d_ptr->extraHeaders;
}
+/*!
+ \internal
+*/
+void QWebEngineUrlRequestInfoPrivate::appendFileToResourceRequestBodyForTest(const QString &path)
+{
+ if (resourceRequestBody)
+ resourceRequestBody->appendFilesForTest(path);
+}
+
QT_END_NAMESPACE
diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h
index 3678b52f4..33efcbeda 100644
--- a/src/core/api/qwebengineurlrequestinfo.h
+++ b/src/core/api/qwebengineurlrequestinfo.h
@@ -7,6 +7,7 @@
#include <QtWebEngineCore/qtwebenginecoreglobal.h>
#include <QtCore/qurl.h>
+#include <QtCore/qiodevice.h>
#include <memory>
@@ -15,6 +16,8 @@ class ContentBrowserClientQt;
class InterceptedRequest;
} // namespace QtWebEngineCore
+class TestPostRequestInterceptor;
+
QT_BEGIN_NAMESPACE
class QWebEngineUrlRequestInfoPrivate;
@@ -68,6 +71,7 @@ public:
QUrl firstPartyUrl() const;
QUrl initiator() const;
QByteArray requestMethod() const;
+ QIODevice *requestBody() const;
bool changed() const;
void block(bool shouldBlock);
@@ -78,6 +82,7 @@ public:
private:
friend class QtWebEngineCore::ContentBrowserClientQt;
friend class QtWebEngineCore::InterceptedRequest;
+ friend class ::TestPostRequestInterceptor;
Q_DISABLE_COPY(QWebEngineUrlRequestInfo)
Q_DECLARE_PRIVATE(QWebEngineUrlRequestInfo)
diff --git a/src/core/api/qwebengineurlrequestinfo_p.h b/src/core/api/qwebengineurlrequestinfo_p.h
index 08faf8323..95cc72362 100644
--- a/src/core/api/qwebengineurlrequestinfo_p.h
+++ b/src/core/api/qwebengineurlrequestinfo_p.h
@@ -27,9 +27,13 @@ namespace net {
class URLRequest;
}
+namespace QtWebEngineCore {
+class ResourceRequestBody;
+}
+
QT_BEGIN_NAMESPACE
-class QWebEngineUrlRequestInfoPrivate
+class Q_WEBENGINECORE_EXPORT QWebEngineUrlRequestInfoPrivate
{
Q_DECLARE_PUBLIC(QWebEngineUrlRequestInfo)
public:
@@ -37,6 +41,7 @@ public:
QWebEngineUrlRequestInfo::NavigationType navigation,
const QUrl &u, const QUrl &fpu, const QUrl &i,
const QByteArray &m,
+ QtWebEngineCore::ResourceRequestBody *const rb = nullptr,
const QHash<QByteArray, QByteArray> &h = {});
QWebEngineUrlRequestInfo::ResourceType resourceType;
@@ -49,8 +54,11 @@ public:
const QByteArray method;
bool changed;
QHash<QByteArray, QByteArray> extraHeaders;
+ QtWebEngineCore::ResourceRequestBody *const resourceRequestBody;
QWebEngineUrlRequestInfo *q_ptr;
+
+ void appendFileToResourceRequestBodyForTest(const QString &path);
};
QT_END_NAMESPACE
diff --git a/src/core/api/qwebengineurlrequestinterceptor.cpp b/src/core/api/qwebengineurlrequestinterceptor.cpp
new file mode 100644
index 000000000..c3cd49a5b
--- /dev/null
+++ b/src/core/api/qwebengineurlrequestinterceptor.cpp
@@ -0,0 +1,11 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwebengineurlrequestinterceptor.h"
+
+QT_BEGIN_NAMESPACE
+
+// Has to stay empty till Qt7
+QWebEngineUrlRequestInterceptor::~QWebEngineUrlRequestInterceptor() = default;
+
+QT_END_NAMESPACE
diff --git a/src/core/api/qwebengineurlrequestinterceptor.h b/src/core/api/qwebengineurlrequestinterceptor.h
index 98f135e73..2ca8ee914 100644
--- a/src/core/api/qwebengineurlrequestinterceptor.h
+++ b/src/core/api/qwebengineurlrequestinterceptor.h
@@ -14,10 +14,9 @@ QT_BEGIN_NAMESPACE
class Q_WEBENGINECORE_EXPORT QWebEngineUrlRequestInterceptor : public QObject
{
Q_OBJECT
- Q_DISABLE_COPY(QWebEngineUrlRequestInterceptor)
public:
explicit QWebEngineUrlRequestInterceptor(QObject *p = nullptr) : QObject(p) {}
-
+ ~QWebEngineUrlRequestInterceptor() override;
virtual void interceptRequest(QWebEngineUrlRequestInfo &info) = 0;
};
diff --git a/src/core/api/qwebengineurlrequestjob.cpp b/src/core/api/qwebengineurlrequestjob.cpp
index 099efef8e..b3997a49d 100644
--- a/src/core/api/qwebengineurlrequestjob.cpp
+++ b/src/core/api/qwebengineurlrequestjob.cpp
@@ -112,13 +112,27 @@ QMap<QByteArray, QByteArray> QWebEngineUrlRequestJob::requestHeaders() const
}
/*!
+ Returns a pointer to a QIODevice that gives access to the request body.
+ The request body can contain data for example when the request is
+ a POST request. If the request body is empty the QIODevice reflects this
+ and does not return any data when performing read operations on it.
+
+ \since 6.7
+ \sa QIODevice
+*/
+QIODevice *QWebEngineUrlRequestJob::requestBody() const
+{
+ return d_ptr->requestBody();
+}
+
+/*!
\since 6.6
Set \a additionalResponseHeaders. These additional headers of the response
are only used when QWebEngineUrlRequestJob::reply(const QByteArray&, QIODevice*)
is called.
*/
void QWebEngineUrlRequestJob::setAdditionalResponseHeaders(
- const QMap<QByteArray, QByteArray> &additionalResponseHeaders) const
+ const QMultiMap<QByteArray, QByteArray> &additionalResponseHeaders) const
{
d_ptr->setAdditionalResponseHeaders(additionalResponseHeaders);
}
diff --git a/src/core/api/qwebengineurlrequestjob.h b/src/core/api/qwebengineurlrequestjob.h
index 75e065566..a0cb48b8b 100644
--- a/src/core/api/qwebengineurlrequestjob.h
+++ b/src/core/api/qwebengineurlrequestjob.h
@@ -39,12 +39,13 @@ public:
QByteArray requestMethod() const;
QUrl initiator() const;
QMap<QByteArray, QByteArray> requestHeaders() const;
+ QIODevice *requestBody() const;
void reply(const QByteArray &contentType, QIODevice *device);
void fail(Error error);
void redirect(const QUrl &url);
void setAdditionalResponseHeaders(
- const QMap<QByteArray, QByteArray> &additionalResponseHeaders) const;
+ const QMultiMap<QByteArray, QByteArray> &additionalResponseHeaders) const;
private:
QWebEngineUrlRequestJob(QtWebEngineCore::URLRequestCustomJobDelegate *);
diff --git a/src/core/api/qwebengineurlscheme.cpp b/src/core/api/qwebengineurlscheme.cpp
index 4af89c616..3093c2b8e 100644
--- a/src/core/api/qwebengineurlscheme.cpp
+++ b/src/core/api/qwebengineurlscheme.cpp
@@ -162,6 +162,11 @@ public:
this includes access from other schemes. The appropriate CORS headers are
generated automatically by the QWebEngineUrlRequestJob class. By default only
\c http and \c https are CORS enabled. (Added in Qt 5.14)
+
+ \value [since 6.6] FetchApiAllowed
+ Enables a URL scheme to be used by the HTML5 fetch API and \c XMLHttpRequest.send with
+ a body. By default only \c http and \c https can be send to using the Fetch API or with
+ an XMLHttpRequest with a body.
*/
QWebEngineUrlScheme::QWebEngineUrlScheme(QWebEngineUrlSchemePrivate *d) : d(d) {}
diff --git a/src/core/api/qwebengineurlscheme.h b/src/core/api/qwebengineurlscheme.h
index 5b6e088cf..35498a68e 100644
--- a/src/core/api/qwebengineurlscheme.h
+++ b/src/core/api/qwebengineurlscheme.h
@@ -42,6 +42,7 @@ public:
ViewSourceAllowed = 0x20,
ContentSecurityPolicyIgnored = 0x40,
CorsEnabled = 0x80,
+ FetchApiAllowed = 0x100,
};
Q_DECLARE_FLAGS(Flags, Flag)
Q_FLAG(Flags)
diff --git a/src/core/api/qwebengineurlschemehandler.cpp b/src/core/api/qwebengineurlschemehandler.cpp
index e78a206d6..e01ecef49 100644
--- a/src/core/api/qwebengineurlschemehandler.cpp
+++ b/src/core/api/qwebengineurlschemehandler.cpp
@@ -12,9 +12,23 @@ QT_BEGIN_NAMESPACE
\brief The QWebEngineUrlSchemeHandler class is a base class for handling custom URL schemes.
\since 5.6
+ A custom scheme handler is, broadly speaking, similar to a web application
+ served over HTTP. However, because custom schemes are integrated directly
+ into the web engine, they have the advantage in terms of efficiency and security:
+ There is no need for generating and parsing HTTP messages or for transferring data
+ over sockets, nor any way to intercept or monitor the traffic.
+
To implement a custom URL scheme for QtWebEngine, you first have to create an instance of
QWebEngineUrlScheme and register it using QWebEngineUrlScheme::registerScheme().
+ As custom schemes are integrated directly into the web engine, they do not
+ necessarily need to follow the standard security rules which apply to
+ ordinary web content. Depending on the chosen configuration, content served
+ over a custom scheme may be given access to local resources, be set to
+ ignore Content-Security-Policy rules, or conversely, be denied access to any
+ other content entirely. If it is to be accessed by normal content, ensure cross-origin
+ access is enabled, and if accessed from HTTPS that it is marked as secure.
+
\note Make sure that you create and register the scheme object \e before the QGuiApplication
or QApplication object is instantiated.
@@ -30,10 +44,23 @@ QT_BEGIN_NAMESPACE
{
public:
MySchemeHandler(QObject *parent = nullptr);
- void requestStarted(QWebEngineUrlRequestJob *request)
+ void requestStarted(QWebEngineUrlRequestJob *job)
{
- // ....
+ const QByteArray method = job->requestMethod();
+ const QUrl url = job->requestUrl();
+
+ if (isValidUrl(url)) {
+ if (method == QByteArrayLiteral("GET")) {
+ job->reply(QByteArrayLiteral("text/html"), makeReply(url));
+ else // Unsupported method
+ job->fail(QWebEngineUrlRequestJob::RequestDenied);
+ } else {
+ // Invalid URL
+ job->fail(QWebEngineUrlRequestJob::UrlNotFound);
+ }
}
+ bool isValidUrl(const QUrl &url) const // ....
+ QIODevice *makeReply(const QUrl &url) // ....
};
int main(int argc, char **argv)
@@ -56,7 +83,7 @@ QT_BEGIN_NAMESPACE
\inmodule QtWebEngineCore
- \sa {QWebEngineUrlScheme}, {WebEngine Widgets WebUI Example}
+ \sa {QWebEngineUrlScheme}
*/
/*!
diff --git a/src/core/api/qwebenginewebauthuxrequest.cpp b/src/core/api/qwebenginewebauthuxrequest.cpp
new file mode 100644
index 000000000..6a79daec9
--- /dev/null
+++ b/src/core/api/qwebenginewebauthuxrequest.cpp
@@ -0,0 +1,427 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qwebenginewebauthuxrequest.h"
+#include "qwebenginewebauthuxrequest_p.h"
+#include "authenticator_request_dialog_controller.h"
+
+/*!
+ \qmltype WebEngineWebAuthUxRequest
+ \instantiates QWebEngineWebAuthUxRequest
+ \inqmlmodule QtWebEngine
+ \since QtWebEngine 6.7
+ \brief Encapsulates the data of a WebAuth UX request.
+
+ Web engine's WebAuth UX requests are passed to the user in the
+ \l WebEngineView::webAuthUxRequested() signal.
+
+ For more information about how to handle web engine authenticator requests, see the
+ \l{WebEngine Quick Nano Browser}{Nano Browser}.
+*/
+
+/*!
+ \class QWebEngineWebAuthUxRequest
+ \brief The QWebEngineWebAuthUxRequest class encapsulates the data of a WebAuth UX request.
+ \since 6.7
+
+ \inmodule QtWebEngineCore
+
+ This class contains the information and API for WebAuth UX. WebAuth may require user
+ interaction during the authentication process. These requests are handled by displaying a
+ dialog to users. QtWebEngine currently supports user verification, resident credentials,
+ and display request failure UX requests.
+
+ QWebEngineWebAuthUxRequest models a WebAuth UX request throughout its life cycle,
+ starting with showing a UX dialog, updating it's content through state changes, and
+ finally closing the dialog.
+
+ WebAuth UX requests are normally triggered when the authenticator requires user interaction.
+ It is the QWebEnginePage's responsibility to notify the application of the new WebAuth UX
+ requests, which it does by emitting the
+ \l{QWebEnginePage::webAuthUxRequested}{webAuthUxRequested} signal together with a newly
+ created QWebEngineWebAuthUxRequest. The application can then examine this request and
+ display a WebAuth UX dialog.
+
+ The QWebEngineWebAuthUxRequest object periodically emits the \l
+ {QWebEngineWebAuthUxRequest::}{stateChanged} signal to notify potential
+ observers of the current WebAuth UX states. The observers update the WebAuth dialog
+ accordingly.
+
+ For more information about how to handle web engine authenticator requests, see the
+ \l{WebEngine Widgets Simple Browser Example}{Simple Browser}.
+*/
+
+/*!
+ \struct QWebEngineWebAuthPinRequest
+ \brief The QWebEngineWebAuthPinRequest class encapsulates the data of a PIN WebAuth UX request.
+ \since 6.7
+
+ \inmodule QtWebEngineCore
+
+ This encapsulates the following information related to a PIN request made by an authenticator.
+ \list
+ \li The reason for the PIN prompt.
+ \li The error details for the PIN prompt.
+ \li The number of attempts remaining before a hard lock. Should be ignored unless
+ \l{QWebEngineWebAuthPinRequest::reason} is
+ \l{QWebEngineWebAuthUxRequest::PinEntryReason::Challenge}.
+ \li The minimum PIN length the authenticator will accept for the PIN.
+ \endlist
+ Use this structure to update the WebAuth UX dialog when the WebAuth UX state is \l
+ QWebEngineWebAuthUxRequest::WebAuthUxState::CollectPin.
+*/
+
+/*!
+ \property QWebEngineWebAuthPinRequest::reason
+ \brief The reason for the PIN prompt.
+*/
+
+/*!
+ \property QWebEngineWebAuthPinRequest::error
+ \brief The error details for the PIN prompt.
+*/
+
+/*!
+ \property QWebEngineWebAuthPinRequest::remainingAttempts
+ \brief The number of attempts remaining before a hard lock. Should be ignored unless
+ \l{QWebEngineWebAuthPinRequest::reason} is
+ \l{QWebEngineWebAuthUxRequest::PinEntryReason::Challenge}.
+*/
+
+/*!
+ \property QWebEngineWebAuthPinRequest::minPinLength
+ \brief The minimum PIN length the authenticator will accept for the PIN.
+*/
+
+/*!
+ \enum QWebEngineWebAuthUxRequest::WebAuthUxState
+
+ This enum describes the state of the current WebAuth UX request.
+
+ \value NotStarted WebAuth UX request not started yet.
+ \value SelectAccount The authenticator requires resident credential details.
+ The application needs to display an account details dialog, and
+ the user needs to select an account to proceed.
+ \value CollectPin The authenticator requires user verification.
+ The application needs to display a PIN request dialog.
+ \value FinishTokenCollection The authenticator requires token/user verification (like tap on
+ the FIDO key) to complete the process.
+ \value RequestFailed WebAuth request failed. Display error details.
+ \value Cancelled WebAuth request is cancelled. Close the WebAuth dialog.
+ \value Completed WebAuth request is completed. Close the WebAuth dialog.
+*/
+
+/*!
+ \enum QWebEngineWebAuthUxRequest::PinEntryReason
+
+ This enum describes the reasons that may prompt the authenticator to ask for a PIN.
+
+ \value Set A new PIN is being set.
+ \value Change The existing PIN must be changed before using this authenticator.
+ \value Challenge The existing PIN is being collected to prove user verification.
+*/
+
+/*!
+ \enum QWebEngineWebAuthUxRequest::PinEntryError
+
+ This enum describes the errors that may prompt the authenticator to ask for a PIN.
+
+ \value NoError No error has occurred.
+ \value InternalUvLocked Internal UV is locked, so we are falling back to PIN.
+ \value WrongPin The PIN the user entered does not match the authenticator PIN.
+ \value TooShort The new PIN the user entered is too short.
+ \value InvalidCharacters The new PIN the user entered contains invalid characters.
+ \value SameAsCurrentPin The new PIN the user entered is the same as the currently set PIN.
+*/
+
+/*!
+ \enum QWebEngineWebAuthUxRequest::RequestFailureReason
+
+ This enum describes the reason for WebAuth request failure.
+
+ \value Timeout The authentication session has timed out.
+ \value KeyNotRegistered Key is not registered with the authenticator.
+ \value KeyAlreadyRegistered Key is already registered with the authenticator.
+ Try to register with another Key or use another authenticator.
+ \value SoftPinBlock The authenticator is blocked as the user entered the wrong key many times.
+ \value HardPinBlock The authenticator is blocked as the user entered the wrong key many times
+ and reset the PIN to use the specific authenticator again.
+ \value AuthenticatorRemovedDuringPinEntry Authenticator removed during PIN entry.
+ \value AuthenticatorMissingResidentKeys Authenticator doesn't have resident key support.
+ \value AuthenticatorMissingUserVerification Authenticator doesn't
+ have user verification support.
+ \value AuthenticatorMissingLargeBlob Authenticator doesn't have large blob support.
+ \value NoCommonAlgorithms No common algorithm.
+ \value StorageFull The resident credential could not be created because the
+ authenticator has insufficient storage.
+ \value UserConsentDenied User consent denied.
+ \value WinUserCancelled The user clicked \uicontrol Cancel in the native windows UI.
+*/
+
+/*!
+ \fn void QWebEngineWebAuthUxRequest::stateChanged(WebAuthUxState state)
+
+ This signal is emitted whenever the WebAuth UX's \a state changes.
+
+ \sa state, WebAuthUxState
+*/
+
+/*!
+ \qmlsignal void WebEngineWebAuthUxRequest::stateChanged(WebAuthUxState state)
+ This signal is emitted whenever the WebAuth UX's \a state changes.
+
+ \sa state, QWebEngineWebAuthUxRequest::WebAuthUxState
+*/
+
+/*! \internal
+ */
+QWebEngineWebAuthUxRequestPrivate::QWebEngineWebAuthUxRequestPrivate(
+ QtWebEngineCore::AuthenticatorRequestDialogController *controller)
+ : webAuthDialogController(controller)
+{
+ m_currentState = controller->state();
+}
+
+/*! \internal
+ */
+QWebEngineWebAuthUxRequestPrivate::~QWebEngineWebAuthUxRequestPrivate() { }
+
+/*! \internal
+ */
+QWebEngineWebAuthUxRequest::QWebEngineWebAuthUxRequest(QWebEngineWebAuthUxRequestPrivate *p)
+ : d_ptr(p)
+{
+ connect(d_ptr->webAuthDialogController,
+ &QtWebEngineCore::AuthenticatorRequestDialogController::stateChanged,
+ [this](WebAuthUxState currentState) {
+ Q_D(QWebEngineWebAuthUxRequest);
+ d->m_currentState = currentState;
+ Q_EMIT stateChanged(d->m_currentState);
+ });
+}
+
+/*! \internal
+ */
+QWebEngineWebAuthUxRequest::~QWebEngineWebAuthUxRequest() { }
+
+/*!
+ \qmlproperty stringlist WebEngineWebAuthUxRequest::userNames
+ \brief The available user names for the resident credential support.
+
+ This is needed when the current WebAuth request's UX state is
+ WebEngineWebAuthUxRequest.WebAuthUxState.SelectAccount. The
+ WebAuth dialog displays user names. The user needs to select an
+ account to proceed.
+
+ \sa state setSelectedAccount() QWebEngineWebAuthUxRequest::userNames
+*/
+/*!
+ \property QWebEngineWebAuthUxRequest::userNames
+ \brief The available user names for the resident credential support.
+ This is needed when the current WebAuth request's UX state is \l SelectAccount.
+ The WebAuth dialog displays user names. The user needs to select an account to proceed.
+
+ \sa SelectAccount setSelectedAccount()
+*/
+QStringList QWebEngineWebAuthUxRequest::userNames() const
+{
+ const Q_D(QWebEngineWebAuthUxRequest);
+
+ return d->webAuthDialogController->userNames();
+}
+
+/*!
+ \qmlproperty string WebEngineWebAuthUxRequest::relyingPartyId
+ \brief The WebAuth request's relying party id.
+*/
+/*!
+ \property QWebEngineWebAuthUxRequest::relyingPartyId
+ \brief The WebAuth request's relying party id.
+*/
+QString QWebEngineWebAuthUxRequest::relyingPartyId() const
+{
+ const Q_D(QWebEngineWebAuthUxRequest);
+
+ return d->webAuthDialogController->relyingPartyId();
+}
+
+/*!
+ \qmlproperty QWebEngineWebAuthPinRequest WebEngineWebAuthUxRequest::pinRequest
+ \brief The WebAuth request's PIN request information.
+
+ \sa QWebEngineWebAuthPinRequest
+*/
+/*!
+ \property QWebEngineWebAuthUxRequest::pinRequest
+ \brief The WebAuth request's PIN request information.
+
+ This is needed when the current WebAuth request state is \l CollectPin.
+ WebAuth Dialog displays a PIN request dialog. The user needs to enter a PIN and
+ invoke \l setPin() to proceed.
+
+ \sa QWebEngineWebAuthPinRequest CollectPin setPin()
+*/
+QWebEngineWebAuthPinRequest QWebEngineWebAuthUxRequest::pinRequest() const
+{
+ const Q_D(QWebEngineWebAuthUxRequest);
+
+ return d->webAuthDialogController->pinRequest();
+}
+
+/*!
+ \qmlproperty enumeration WebEngineWebAuthUxRequest::state
+ \brief The WebAuth request's current UX state.
+
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.NotStarted WebAuth UX request not started yet.
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.SelectAccount The authenticator requires
+ resident credential details. The application needs to display an account details dialog,
+ and the user needs to select an account to proceed.
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.CollectPin The authenticator requires user verification.
+ The application needs to display a PIN request dialog.
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.FinishTokenCollection The authenticator requires
+ token/user verification (like tap on the FIDO key) to complete the process.
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.RequestFailed WebAuth request failed. Display error details.
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.Cancelled WebAuth request is cancelled.
+ Close the WebAuth dialog.
+ \value WebEngineWebAuthUxRequest.WebAuthUxState.Completed WebAuth request is completed.
+ Close the WebAuth dialog.
+*/
+/*!
+ \property QWebEngineWebAuthUxRequest::state
+ \brief The WebAuth request's current UX state.
+
+ \l stateChanged() is emitted when the current state changes.
+ Update the WebAuth dialog in reponse to the changes in state.
+*/
+QWebEngineWebAuthUxRequest::WebAuthUxState QWebEngineWebAuthUxRequest::state() const
+{
+ return d_ptr->m_currentState;
+}
+
+/*!
+ \qmlmethod void WebEngineWebAuthUxRequest::setSelectedAccount(const QString &selectedAccount)
+
+ Sends the \a selectedAccount name to the authenticator.
+ This is needed when the current WebAuth request's UX state is
+ WebEngineWebAuthUxRequest.WebAuthUxState.SelectAccount. The
+ WebAuth request is blocked until the user selects an account and
+ invokes this method.
+
+ \sa WebEngineWebAuthUxRequest::userNames state
+*/
+/*!
+ Sends the \a selectedAccount name to the authenticator.
+ This is needed when the current WebAuth request's UX state is \l SelectAccount.
+ The WebAuth request is blocked until the user selects an account and invokes this method.
+
+ \sa userNames SelectAccount
+*/
+void QWebEngineWebAuthUxRequest::setSelectedAccount(const QString &selectedAccount)
+{
+ Q_D(QWebEngineWebAuthUxRequest);
+
+ d->webAuthDialogController->sendSelectAccountResponse(selectedAccount);
+}
+
+/*!
+ \qmlmethod void WebEngineWebAuthUxRequest::setPin(const QString &pin)
+ Sends the \a pin to the authenticator that prompts for a PIN.
+ This is needed when the current WebAuth request's UX state is
+ WebEngineWebAuthUxRequest.WebAuthUxState.CollectPin. The WebAuth
+ request is blocked until the user responds with a PIN.
+
+ \sa QWebEngineWebAuthPinRequest state
+*/
+/*!
+ Sends the \a pin to the authenticator that prompts for a PIN.
+ This is needed when the current WebAuth request's UX state is \l CollectPin.
+ The WebAuth request is blocked until the user responds with a PIN.
+
+ \sa QWebEngineWebAuthPinRequest CollectPin
+*/
+void QWebEngineWebAuthUxRequest::setPin(const QString &pin)
+{
+ Q_D(QWebEngineWebAuthUxRequest);
+ d->webAuthDialogController->sendCollectPinResponse(pin);
+}
+
+/*!
+ \qmlmethod void WebEngineWebAuthUxRequest::cancel()
+ Cancels the current WebAuth request.
+
+ \sa QWebEngineWebAuthUxRequest::Cancelled, WebEngineWebAuthUxRequest::stateChanged()
+*/
+/*!
+ Cancels the current WebAuth request.
+
+ \sa QWebEngineWebAuthUxRequest::Cancelled, stateChanged()
+*/
+void QWebEngineWebAuthUxRequest::cancel()
+{
+ Q_D(QWebEngineWebAuthUxRequest);
+
+ d->webAuthDialogController->reject();
+}
+
+/*!
+ \qmlmethod void WebEngineWebAuthUxRequest::retry()
+ Retries the current WebAuth request.
+
+ \sa stateChanged()
+*/
+/*!
+ Retries the current WebAuth request.
+
+ \sa stateChanged()
+*/
+void QWebEngineWebAuthUxRequest::retry()
+{
+ const Q_D(QWebEngineWebAuthUxRequest);
+
+ d->webAuthDialogController->retryRequest();
+}
+
+/*!
+ \qmlproperty enumeration WebEngineWebAuthUxRequest::requestFailureReason
+ \brief The WebAuth request's failure reason.
+
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.Timeout The authentication session has timed out.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.KeyNotRegistered Key is not registered with the authenticator.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.KeyAlreadyRegistered Key is already registered with
+ the authenticator. Try to register with another key or use another authenticator.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.SoftPinBlock The authenticator is blocked as the user
+ entered the wrong key many times.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.HardPinBlock The authenticator is blocked as the user entered
+ the wrong key many times and reset the PIN to use the specific authenticator again.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorRemovedDuringPinEntry Authenticator
+ removed during PIN entry.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorMissingResidentKeys Authenticator doesn't
+ have resident key support.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorMissingUserVerification Authenticator doesn't
+ have user verification support.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.AuthenticatorMissingLargeBlob Authenticator doesn't have
+ large blob support.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.NoCommonAlgorithms No common algorithm.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.StorageFull The resident credential could not be created
+ because the authenticator has insufficient storage.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.UserConsentDenied User consent denied.
+ \value WebEngineWebAuthUxRequest.RequestFailureReason.WinUserCancelled The user clicked \uicontrol Cancel
+ in the native windows UI.
+
+ \sa stateChanged()
+*/
+/*!
+ \property QWebEngineWebAuthUxRequest::requestFailureReason
+ \brief The WebAuth request's failure reason.
+
+ \sa stateChanged() QWebEngineWebAuthUxRequest::RequestFailureReason
+*/
+QWebEngineWebAuthUxRequest::RequestFailureReason
+QWebEngineWebAuthUxRequest::requestFailureReason() const
+{
+ const Q_D(QWebEngineWebAuthUxRequest);
+
+ return d->webAuthDialogController->requestFailureReason();
+}
+
+#include "moc_qwebenginewebauthuxrequest.cpp"
diff --git a/src/core/api/qwebenginewebauthuxrequest.h b/src/core/api/qwebenginewebauthuxrequest.h
new file mode 100644
index 000000000..111f52847
--- /dev/null
+++ b/src/core/api/qwebenginewebauthuxrequest.h
@@ -0,0 +1,117 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINEWEBAUTHUXREQUEST_H
+#define QWEBENGINEWEBAUTHUXREQUEST_H
+
+#include <QtWebEngineCore/qtwebenginecoreglobal.h>
+#include <QtCore/qobject.h>
+
+namespace QtWebEngineCore {
+class AuthenticatorRequestDialogControllerPrivate;
+}
+
+QT_BEGIN_NAMESPACE
+
+class QWebEngineWebAuthUxRequestPrivate;
+struct QWebEngineWebAuthPinRequest;
+
+class Q_WEBENGINECORE_EXPORT QWebEngineWebAuthUxRequest : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QStringList userNames READ userNames CONSTANT FINAL)
+ Q_PROPERTY(WebAuthUxState state READ state NOTIFY stateChanged FINAL)
+ Q_PROPERTY(QString relyingPartyId READ relyingPartyId CONSTANT FINAL)
+ Q_PROPERTY(QWebEngineWebAuthPinRequest pinRequest READ pinRequest CONSTANT FINAL)
+ Q_PROPERTY(RequestFailureReason requestFailureReason READ requestFailureReason CONSTANT FINAL)
+ Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
+public:
+ enum class WebAuthUxState {
+ NotStarted,
+ SelectAccount,
+ CollectPin,
+ FinishTokenCollection,
+ RequestFailed,
+ Cancelled,
+ Completed,
+ };
+ Q_ENUM(WebAuthUxState)
+
+ enum class PinEntryReason {
+ Set,
+ Change,
+ Challenge,
+ };
+ Q_ENUM(PinEntryReason)
+
+ enum class PinEntryError {
+ NoError,
+ InternalUvLocked,
+ WrongPin,
+ TooShort,
+ InvalidCharacters,
+ SameAsCurrentPin,
+ };
+ Q_ENUM(PinEntryError)
+
+ enum class RequestFailureReason {
+ Timeout,
+ KeyNotRegistered,
+ KeyAlreadyRegistered,
+ SoftPinBlock,
+ HardPinBlock,
+ AuthenticatorRemovedDuringPinEntry,
+ AuthenticatorMissingResidentKeys,
+ AuthenticatorMissingUserVerification,
+ AuthenticatorMissingLargeBlob,
+ NoCommonAlgorithms,
+ StorageFull,
+ UserConsentDenied,
+ WinUserCancelled,
+ };
+ Q_ENUM(RequestFailureReason)
+
+ ~QWebEngineWebAuthUxRequest() override;
+
+ QStringList userNames() const;
+ QString relyingPartyId() const;
+ QWebEngineWebAuthPinRequest pinRequest() const;
+ WebAuthUxState state() const;
+ RequestFailureReason requestFailureReason() const;
+
+Q_SIGNALS:
+ void stateChanged(QWebEngineWebAuthUxRequest::WebAuthUxState state);
+
+public Q_SLOTS:
+ void cancel();
+ void retry();
+ void setSelectedAccount(const QString &selectedAccount);
+ void setPin(const QString &pin);
+
+protected:
+ explicit QWebEngineWebAuthUxRequest(QWebEngineWebAuthUxRequestPrivate *);
+
+ std::unique_ptr<QWebEngineWebAuthUxRequestPrivate> d_ptr;
+ friend class QtWebEngineCore::AuthenticatorRequestDialogControllerPrivate;
+ Q_DECLARE_PRIVATE(QWebEngineWebAuthUxRequest)
+};
+
+struct QWebEngineWebAuthPinRequest
+{
+ Q_GADGET_EXPORT(Q_WEBENGINECORE_EXPORT)
+
+ Q_PROPERTY(QWebEngineWebAuthUxRequest::PinEntryReason reason MEMBER reason CONSTANT FINAL)
+ Q_PROPERTY(QWebEngineWebAuthUxRequest::PinEntryError error MEMBER error CONSTANT FINAL)
+ Q_PROPERTY(qint32 minPinLength MEMBER minPinLength CONSTANT FINAL)
+ Q_PROPERTY(int remainingAttempts MEMBER remainingAttempts CONSTANT FINAL)
+public:
+ QWebEngineWebAuthUxRequest::PinEntryReason reason;
+ QWebEngineWebAuthUxRequest::PinEntryError error;
+ qint32 minPinLength;
+ int remainingAttempts;
+};
+
+QT_END_NAMESPACE
+
+#endif // QWEBENGINEWEBAUTHUXREQUEST_H
diff --git a/src/core/api/qwebenginewebauthuxrequest_p.h b/src/core/api/qwebenginewebauthuxrequest_p.h
new file mode 100644
index 000000000..4c685bac7
--- /dev/null
+++ b/src/core/api/qwebenginewebauthuxrequest_p.h
@@ -0,0 +1,43 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QWEBENGINEWEBAUTHUXREQUEST_P_H
+#define QWEBENGINEWEBAUTHUXREQUEST_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 "qtwebenginecoreglobal_p.h"
+#include "qwebenginewebauthuxrequest.h"
+#include <QtCore/QSharedPointer>
+
+namespace QtWebEngineCore {
+class WebContentsAdapterClient;
+class AuthenticatorRequestDialogController;
+}
+
+QT_BEGIN_NAMESPACE
+
+class Q_WEBENGINECORE_EXPORT QWebEngineWebAuthUxRequestPrivate
+{
+
+public:
+ QWebEngineWebAuthUxRequestPrivate(
+ QtWebEngineCore::AuthenticatorRequestDialogController *controller);
+ ~QWebEngineWebAuthUxRequestPrivate();
+
+ QWebEngineWebAuthUxRequest::WebAuthUxState m_currentState =
+ QWebEngineWebAuthUxRequest::WebAuthUxState::NotStarted;
+ QtWebEngineCore::AuthenticatorRequestDialogController *webAuthDialogController;
+};
+
+QT_END_NAMESPACE
+#endif // QWEBENGINEWEBAUTHUXREQUEST_P_H
diff --git a/src/core/authentication_dialog_controller.h b/src/core/authentication_dialog_controller.h
index ea8d9035e..944ec4d15 100644
--- a/src/core/authentication_dialog_controller.h
+++ b/src/core/authentication_dialog_controller.h
@@ -22,7 +22,7 @@ namespace QtWebEngineCore {
class AuthenticationDialogControllerPrivate;
-class Q_WEBENGINECORE_PRIVATE_EXPORT AuthenticationDialogController : public QObject {
+class Q_WEBENGINECORE_EXPORT AuthenticationDialogController : public QObject {
Q_OBJECT
public:
~AuthenticationDialogController();
diff --git a/src/core/authenticator_request_client_delegate_qt.cpp b/src/core/authenticator_request_client_delegate_qt.cpp
new file mode 100644
index 000000000..5f9fd9ca3
--- /dev/null
+++ b/src/core/authenticator_request_client_delegate_qt.cpp
@@ -0,0 +1,247 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "authenticator_request_client_delegate_qt.h"
+#include "authenticator_request_dialog_controller.h"
+#include "authenticator_request_dialog_controller_p.h"
+#include "base/base64.h"
+#include "profile_adapter_client.h"
+#include "profile_qt.h"
+#include "content/public/browser/web_contents.h"
+#include "web_contents_delegate_qt.h"
+#include "type_conversion.h"
+
+namespace QtWebEngineCore {
+
+using RequestFailureReason = QWebEngineWebAuthUxRequest::RequestFailureReason;
+
+WebAuthenticationDelegateQt::WebAuthenticationDelegateQt() = default;
+
+WebAuthenticationDelegateQt::~WebAuthenticationDelegateQt() = default;
+
+bool WebAuthenticationDelegateQt::SupportsResidentKeys(content::RenderFrameHost *render_frame_host)
+{
+ return true;
+}
+
+AuthenticatorRequestClientDelegateQt::AuthenticatorRequestClientDelegateQt(
+ content::RenderFrameHost *render_frame_host)
+ : m_renderFrameHost(render_frame_host), m_weakFactory(this)
+{
+ m_dialogController.reset(new AuthenticatorRequestDialogController(
+ new AuthenticatorRequestDialogControllerPrivate(m_renderFrameHost,
+ m_weakFactory.GetWeakPtr())));
+}
+
+AuthenticatorRequestClientDelegateQt::~AuthenticatorRequestClientDelegateQt()
+{
+ // Currently WebAuth request is completed. Now it is possible to delete the dialog if displayed
+ m_dialogController->finishRequest();
+}
+
+void AuthenticatorRequestClientDelegateQt::SetRelyingPartyId(const std::string &rp_id)
+{
+ m_dialogController->setRelyingPartyId(rp_id);
+}
+
+bool AuthenticatorRequestClientDelegateQt::DoesBlockRequestOnFailure(
+ InterestingFailureReason reason)
+{
+ if (!IsWebAuthnUIEnabled())
+ return false;
+
+ switch (reason) {
+ case InterestingFailureReason::kTimeout:
+ m_dialogController->handleRequestFailure(RequestFailureReason::Timeout);
+ break;
+ case InterestingFailureReason::kAuthenticatorMissingResidentKeys:
+ m_dialogController->handleRequestFailure(
+ RequestFailureReason::AuthenticatorMissingResidentKeys);
+ break;
+ case InterestingFailureReason::kAuthenticatorMissingUserVerification:
+ m_dialogController->handleRequestFailure(
+ RequestFailureReason::AuthenticatorMissingUserVerification);
+ break;
+ case InterestingFailureReason::kAuthenticatorMissingLargeBlob:
+ m_dialogController->handleRequestFailure(
+ RequestFailureReason::AuthenticatorMissingLargeBlob);
+ break;
+ case InterestingFailureReason::kAuthenticatorRemovedDuringPINEntry:
+ m_dialogController->handleRequestFailure(
+ RequestFailureReason::AuthenticatorRemovedDuringPinEntry);
+ break;
+ case InterestingFailureReason::kHardPINBlock:
+ m_dialogController->handleRequestFailure(RequestFailureReason::HardPinBlock);
+ break;
+ case InterestingFailureReason::kSoftPINBlock:
+ m_dialogController->handleRequestFailure(RequestFailureReason::SoftPinBlock);
+ break;
+ case InterestingFailureReason::kKeyAlreadyRegistered:
+ m_dialogController->handleRequestFailure(RequestFailureReason::KeyAlreadyRegistered);
+ break;
+ case InterestingFailureReason::kKeyNotRegistered:
+ m_dialogController->handleRequestFailure(RequestFailureReason::KeyNotRegistered);
+ break;
+ case InterestingFailureReason::kNoCommonAlgorithms:
+ m_dialogController->handleRequestFailure(RequestFailureReason::NoCommonAlgorithms);
+ break;
+ case InterestingFailureReason::kStorageFull:
+ m_dialogController->handleRequestFailure(RequestFailureReason::StorageFull);
+ break;
+ case InterestingFailureReason::kUserConsentDenied:
+ m_dialogController->handleRequestFailure(RequestFailureReason::UserConsentDenied);
+ break;
+ case InterestingFailureReason::kWinUserCancelled:
+#if BUILDFLAG(IS_WIN)
+ m_dialogController->handleRequestFailure(RequestFailureReason::WinUserCancelled);
+#else
+ return false;
+#endif
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+void AuthenticatorRequestClientDelegateQt::RegisterActionCallbacks(
+ base::OnceClosure cancel_callback, base::RepeatingClosure start_over_callback,
+ AccountPreselectedCallback account_preselected_callback,
+ device::FidoRequestHandlerBase::RequestCallback request_callback,
+ base::RepeatingClosure bluetooth_adapter_power_on_callback)
+{
+ m_cancelCallback = std::move(cancel_callback);
+ m_startOverCallback = std::move(start_over_callback);
+ m_accountPreselectedCallback = std::move(account_preselected_callback);
+ m_requestCallback = std::move(request_callback);
+ m_bluetoothAdapterPowerOnCallback = std::move(bluetooth_adapter_power_on_callback);
+}
+
+void AuthenticatorRequestClientDelegateQt::ShouldReturnAttestation(
+ const std::string &relying_party_id, const device::FidoAuthenticator *authenticator,
+ bool is_enterprise_attestation, base::OnceCallback<void(bool)> callback)
+{
+ std::move(callback).Run(!is_enterprise_attestation);
+}
+
+void AuthenticatorRequestClientDelegateQt::SelectAccount(
+ std::vector<device::AuthenticatorGetAssertionResponse> responses,
+ base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)> callback)
+{
+ if (m_isUiDisabled) {
+ // Requests with UI disabled should never reach account selection.
+ DCHECK(IsVirtualEnvironmentEnabled());
+ std::move(callback).Run(std::move(responses.at(0)));
+ return;
+ }
+
+ if (m_isConditionalRequest) {
+ return;
+ }
+
+ m_authenticatorGetAssertionResponse = std::move(responses);
+ m_selectAccountCallback = std::move(callback);
+
+ QStringList userList;
+ int nIndex = -1;
+ for (const auto &response : m_authenticatorGetAssertionResponse) {
+ nIndex++;
+ const auto &user_entity = response.user_entity;
+ const bool has_user_identifying_info = user_entity && user_entity->name;
+ if (has_user_identifying_info) {
+ QString userName = toQt(*response.user_entity->name);
+ m_userMap[userName] = nIndex;
+ userList.append(userName);
+ }
+ }
+ m_dialogController->selectAccount(userList);
+}
+
+void AuthenticatorRequestClientDelegateQt::DisableUI()
+{
+ m_isUiDisabled = true;
+}
+
+bool AuthenticatorRequestClientDelegateQt::IsWebAuthnUIEnabled()
+{
+ return !m_isUiDisabled;
+}
+
+void AuthenticatorRequestClientDelegateQt::SetConditionalRequest(bool is_conditional)
+{
+ m_isConditionalRequest = is_conditional;
+}
+
+// This method will not be invoked until the observer is set.
+void AuthenticatorRequestClientDelegateQt::OnTransportAvailabilityEnumerated(
+ device::FidoRequestHandlerBase::TransportAvailabilityInfo data)
+{
+ // Show dialog only after this step;
+ // If m_isUiDisabled is set or another UI request in progress return
+ if (m_isUiDisabled
+ || m_dialogController->state() != QWebEngineWebAuthUxRequest::WebAuthUxState::NotStarted)
+ return;
+
+ // Start WebAuth UX
+ // we may need to pass data as well. for SelectAccount and SupportPin it is not required,
+ // skipping that for the timebeing.
+ m_dialogController->startRequest(m_isConditionalRequest);
+}
+
+bool AuthenticatorRequestClientDelegateQt::SupportsPIN() const
+{
+ return true;
+}
+
+void AuthenticatorRequestClientDelegateQt::CollectPIN(
+ CollectPINOptions options, base::OnceCallback<void(std::u16string)> provide_pin_cb)
+{
+
+ m_providePinCallback = std::move(provide_pin_cb);
+ QWebEngineWebAuthPinRequest pinRequestInfo;
+
+ pinRequestInfo.reason = static_cast<QWebEngineWebAuthUxRequest::PinEntryReason>(options.reason);
+ pinRequestInfo.error = static_cast<QWebEngineWebAuthUxRequest::PinEntryError>(options.error);
+ pinRequestInfo.remainingAttempts = options.attempts;
+ pinRequestInfo.minPinLength = options.min_pin_length;
+ m_dialogController->collectPin(pinRequestInfo);
+}
+
+void AuthenticatorRequestClientDelegateQt::FinishCollectToken()
+{
+ m_dialogController->finishCollectToken();
+}
+
+void AuthenticatorRequestClientDelegateQt::onCancelRequest()
+{
+ if (!m_cancelCallback)
+ return;
+
+ std::move(m_cancelCallback).Run();
+}
+
+void AuthenticatorRequestClientDelegateQt::onSelectAccount(const QString &selectedAccount)
+{
+ if (!m_selectAccountCallback)
+ return;
+
+ if (m_userMap.find(selectedAccount) != m_userMap.end()) {
+ std::move(m_selectAccountCallback)
+ .Run(std::move(m_authenticatorGetAssertionResponse.at(m_userMap[selectedAccount])));
+ } else {
+ onCancelRequest();
+ }
+}
+
+void AuthenticatorRequestClientDelegateQt::onCollectPin(const QString &pin)
+{
+ if (!m_providePinCallback)
+ return;
+ std::move(m_providePinCallback).Run(pin.toStdU16String());
+}
+
+void AuthenticatorRequestClientDelegateQt::onRetryRequest()
+{
+ DCHECK(m_startOverCallback);
+ m_startOverCallback.Run();
+}
+}
diff --git a/src/core/authenticator_request_client_delegate_qt.h b/src/core/authenticator_request_client_delegate_qt.h
new file mode 100644
index 000000000..05c6136bd
--- /dev/null
+++ b/src/core/authenticator_request_client_delegate_qt.h
@@ -0,0 +1,96 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef AUTHENTICATOR_REQUEST_CLIENT_DELEGATE_QT_H
+#define AUTHENTICATOR_REQUEST_CLIENT_DELEGATE_QT_H
+
+#include "qtwebenginecoreglobal_p.h"
+#include "content/public/browser/authenticator_request_client_delegate.h"
+#include <unordered_map>
+#include <QSharedPointer>
+
+namespace QtWebEngineCore {
+
+class AuthenticatorRequestDialogController;
+
+class WebAuthenticationDelegateQt : public content::WebAuthenticationDelegate
+{
+public:
+ WebAuthenticationDelegateQt();
+ virtual ~WebAuthenticationDelegateQt();
+
+ bool SupportsResidentKeys(content::RenderFrameHost *render_frame_host) override;
+};
+
+class AuthenticatorRequestClientDelegateQt : public content::AuthenticatorRequestClientDelegate
+{
+public:
+ explicit AuthenticatorRequestClientDelegateQt(content::RenderFrameHost *render_frame_host);
+ AuthenticatorRequestClientDelegateQt(const AuthenticatorRequestClientDelegateQt &) = delete;
+ AuthenticatorRequestClientDelegateQt &
+ operator=(const AuthenticatorRequestClientDelegateQt &) = delete;
+ ~AuthenticatorRequestClientDelegateQt();
+
+ // content::AuthenticatorRequestClientDelegate ovverrides
+ void SetRelyingPartyId(const std::string &rp_id) override;
+ bool DoesBlockRequestOnFailure(InterestingFailureReason reason) override;
+ void RegisterActionCallbacks(base::OnceClosure cancel_callback,
+ base::RepeatingClosure start_over_callback,
+ AccountPreselectedCallback account_preselected_callback,
+ device::FidoRequestHandlerBase::RequestCallback request_callback,
+ base::RepeatingClosure bluetooth_adapter_power_on_callback) override;
+ void ShouldReturnAttestation(const std::string &relying_party_id,
+ const device::FidoAuthenticator *authenticator,
+ bool is_enterprise_attestation,
+ base::OnceCallback<void(bool)> callback) override;
+ void SelectAccount(
+ std::vector<device::AuthenticatorGetAssertionResponse> responses,
+ base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)> callback) override;
+ void DisableUI() override;
+ bool IsWebAuthnUIEnabled() override;
+ void SetConditionalRequest(bool is_conditional) override;
+
+ // device::FidoRequestHandlerBase::Observer overrides:
+ // This method will not be invoked until the observer is set.
+ void OnTransportAvailabilityEnumerated(
+ device::FidoRequestHandlerBase::TransportAvailabilityInfo data) override;
+
+ bool SupportsPIN() const override;
+ void CollectPIN(CollectPINOptions options,
+ base::OnceCallback<void(std::u16string)> provide_pin_cb) override;
+ void FinishCollectToken() override;
+
+ // Dialog helper
+ void onCancelRequest();
+ void onSelectAccount(const QString &selectedAccount);
+ void onCollectPin(const QString &pin);
+ void onRetryRequest();
+
+private:
+ content::RenderFrameHost *m_renderFrameHost;
+ bool m_isUiDisabled = false;
+ bool m_isConditionalRequest = false;
+
+ base::OnceClosure m_cancelCallback;
+ base::RepeatingClosure m_startOverCallback;
+ AccountPreselectedCallback m_accountPreselectedCallback;
+ device::FidoRequestHandlerBase::RequestCallback m_requestCallback;
+ base::RepeatingClosure m_bluetoothAdapterPowerOnCallback;
+
+ // Select account details;
+ std::vector<device::AuthenticatorGetAssertionResponse> m_authenticatorGetAssertionResponse;
+ std::unordered_map<QString, int> m_userMap;
+ base::OnceCallback<void(device::AuthenticatorGetAssertionResponse)> m_selectAccountCallback;
+
+ // collect pin
+ base::OnceCallback<void(std::u16string)> m_providePinCallback;
+
+ // This member is used to keep authenticator request dialog controller alive until
+ // authenticator request is completed or cancelled.
+ QSharedPointer<AuthenticatorRequestDialogController> m_dialogController;
+ base::WeakPtrFactory<AuthenticatorRequestClientDelegateQt> m_weakFactory;
+};
+
+}
+
+#endif // AUTHENTICATOR_REQUEST_CLIENT_DELEGATE_QT_H
diff --git a/src/core/authenticator_request_dialog_controller.cpp b/src/core/authenticator_request_dialog_controller.cpp
new file mode 100644
index 000000000..73fb4e7f3
--- /dev/null
+++ b/src/core/authenticator_request_dialog_controller.cpp
@@ -0,0 +1,302 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "authenticator_request_dialog_controller.h"
+#include "authenticator_request_dialog_controller_p.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "web_contents_delegate_qt.h"
+#include "qwebenginewebauthuxrequest_p.h"
+#include "qwebenginewebauthuxrequest.h"
+
+using PinEntryError = QWebEngineWebAuthUxRequest::PinEntryError;
+using PinEntryReason = QWebEngineWebAuthUxRequest::PinEntryReason;
+using WebAuthUxState = QWebEngineWebAuthUxRequest::WebAuthUxState;
+
+namespace QtWebEngineCore {
+
+ASSERT_ENUMS_MATCH(PinEntryReason::Set, device::pin::PINEntryReason::kSet)
+ASSERT_ENUMS_MATCH(PinEntryReason::Change, device::pin::PINEntryReason::kChange)
+ASSERT_ENUMS_MATCH(PinEntryReason::Challenge, device::pin::PINEntryReason::kChallenge)
+ASSERT_ENUMS_MATCH(PinEntryError::WrongPin, device::pin::PINEntryError::kWrongPIN)
+ASSERT_ENUMS_MATCH(PinEntryError::TooShort, device::pin::PINEntryError::kTooShort)
+ASSERT_ENUMS_MATCH(PinEntryError::SameAsCurrentPin, device::pin::PINEntryError::kSameAsCurrentPIN)
+ASSERT_ENUMS_MATCH(PinEntryError::NoError, device::pin::PINEntryError::kNoError)
+ASSERT_ENUMS_MATCH(PinEntryError::InvalidCharacters, device::pin::PINEntryError::kInvalidCharacters)
+ASSERT_ENUMS_MATCH(PinEntryError::InternalUvLocked, device::pin::PINEntryError::kInternalUvLocked)
+
+AuthenticatorRequestDialogControllerPrivate::AuthenticatorRequestDialogControllerPrivate(
+ content::RenderFrameHost *renderFrameHost,
+ base::WeakPtr<AuthenticatorRequestClientDelegateQt> authenticatorRequestDelegate)
+ : m_renderFrameHost(renderFrameHost)
+ , m_authenticatorRequestDelegate(authenticatorRequestDelegate)
+{
+}
+
+AuthenticatorRequestDialogControllerPrivate::~AuthenticatorRequestDialogControllerPrivate()
+{
+ if (m_request) {
+ delete m_request;
+ m_request = nullptr;
+ }
+}
+
+void AuthenticatorRequestDialogControllerPrivate::showWebAuthDialog()
+{
+ Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ content::WebContents *webContent = content::WebContents::FromRenderFrameHost(m_renderFrameHost);
+
+ if (!webContent)
+ return;
+
+ WebContentsAdapterClient *adapterClient = nullptr;
+ if (webContent)
+ adapterClient =
+ static_cast<WebContentsDelegateQt *>(webContent->GetDelegate())->adapterClient();
+
+ if (adapterClient) {
+
+ QWebEngineWebAuthUxRequestPrivate *itemPrivate =
+ new QWebEngineWebAuthUxRequestPrivate(q_ptr);
+
+ m_request = new QWebEngineWebAuthUxRequest(itemPrivate);
+
+ adapterClient->showWebAuthDialog(m_request);
+ m_isDialogCreated = true;
+ } else {
+ cancelRequest();
+ }
+}
+
+void AuthenticatorRequestDialogControllerPrivate::selectAccount(const QStringList &userList)
+{
+ m_userList.clear();
+ m_userList = userList;
+ setCurrentState(WebAuthUxState::SelectAccount);
+}
+
+void AuthenticatorRequestDialogControllerPrivate::collectPin(QWebEngineWebAuthPinRequest pinRequest)
+{
+ m_pinRequest = pinRequest;
+ setCurrentState(WebAuthUxState::CollectPin);
+}
+
+void AuthenticatorRequestDialogControllerPrivate::finishCollectToken()
+{
+ setCurrentState(WebAuthUxState::FinishTokenCollection);
+}
+
+QStringList AuthenticatorRequestDialogControllerPrivate::userNames() const
+{
+ return m_userList;
+}
+
+void AuthenticatorRequestDialogControllerPrivate::finishRequest()
+{
+ if (!m_isDialogCreated)
+ return;
+ setCurrentState(WebAuthUxState::Completed);
+}
+
+void AuthenticatorRequestDialogControllerPrivate::setCurrentState(
+ QWebEngineWebAuthUxRequest::WebAuthUxState uxState)
+{
+ if (!m_isStarted) {
+ // Dialog isn't showing yet. Remember to show this step when it appears.
+ m_pendingState = uxState;
+ return;
+ }
+
+ m_currentState = uxState;
+
+ if (m_isConditionalRequest)
+ return;
+
+ if (!m_isDialogCreated) {
+ showWebAuthDialog();
+ } else {
+ Q_EMIT q_ptr->stateChanged(m_currentState);
+
+ if (m_currentState == QWebEngineWebAuthUxRequest::WebAuthUxState::Cancelled
+ || m_currentState == QWebEngineWebAuthUxRequest::WebAuthUxState::Completed) {
+ m_isDialogCreated = false;
+ }
+ }
+}
+
+void AuthenticatorRequestDialogControllerPrivate::cancelRequest()
+{
+ setCurrentState(WebAuthUxState::Cancelled);
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AuthenticatorRequestClientDelegateQt::onCancelRequest,
+ m_authenticatorRequestDelegate));
+}
+
+void AuthenticatorRequestDialogControllerPrivate::retryRequest()
+{
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AuthenticatorRequestClientDelegateQt::onRetryRequest,
+ m_authenticatorRequestDelegate));
+}
+
+void AuthenticatorRequestDialogControllerPrivate::sendSelectAccountResponse(
+ const QString &selectedAccount)
+{
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AuthenticatorRequestClientDelegateQt::onSelectAccount,
+ m_authenticatorRequestDelegate, selectedAccount));
+}
+
+QWebEngineWebAuthUxRequest::WebAuthUxState
+AuthenticatorRequestDialogControllerPrivate::state() const
+{
+ return m_currentState;
+}
+
+void AuthenticatorRequestDialogControllerPrivate::startRequest(bool isConditionalRequest)
+{
+ DCHECK(!m_isStarted);
+
+ m_isStarted = true;
+ m_isConditionalRequest = isConditionalRequest;
+
+ if (m_pendingState) {
+ setCurrentState(*m_pendingState);
+ m_pendingState.reset();
+ }
+}
+
+void AuthenticatorRequestDialogControllerPrivate::setRelyingPartyId(const QString &rpId)
+{
+ m_relyingPartyId = rpId;
+}
+
+QString AuthenticatorRequestDialogControllerPrivate::relyingPartyId() const
+{
+ return m_relyingPartyId;
+}
+
+QWebEngineWebAuthPinRequest AuthenticatorRequestDialogControllerPrivate::pinRequest()
+{
+ return m_pinRequest;
+}
+
+void AuthenticatorRequestDialogControllerPrivate::handleRequestFailure(
+ QWebEngineWebAuthUxRequest::RequestFailureReason reason)
+{
+ m_requestFailureReason = reason;
+ setCurrentState(WebAuthUxState::RequestFailed);
+}
+
+void AuthenticatorRequestDialogControllerPrivate::sendCollectPinResponse(const QString &pin)
+{
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&AuthenticatorRequestClientDelegateQt::onCollectPin,
+ m_authenticatorRequestDelegate, pin));
+}
+
+QWebEngineWebAuthUxRequest::RequestFailureReason
+AuthenticatorRequestDialogControllerPrivate::requestFailureReason() const
+{
+ return m_requestFailureReason;
+}
+
+AuthenticatorRequestDialogController::AuthenticatorRequestDialogController(
+ AuthenticatorRequestDialogControllerPrivate *dd)
+{
+ Q_ASSERT(dd);
+ d_ptr.reset(dd);
+ d_ptr->q_ptr = this;
+}
+
+AuthenticatorRequestDialogController::~AuthenticatorRequestDialogController() { }
+
+void AuthenticatorRequestDialogController::selectAccount(const QStringList &userList)
+{
+ d_ptr->selectAccount(userList);
+}
+
+void AuthenticatorRequestDialogController::collectPin(QWebEngineWebAuthPinRequest pinRequest)
+{
+ d_ptr->collectPin(pinRequest);
+}
+
+QStringList AuthenticatorRequestDialogController::userNames() const
+{
+ return d_ptr->userNames();
+}
+
+QWebEngineWebAuthPinRequest AuthenticatorRequestDialogController::pinRequest()
+{
+ return d_ptr->pinRequest();
+}
+
+void AuthenticatorRequestDialogController::reject()
+{
+ d_ptr->cancelRequest();
+}
+
+void AuthenticatorRequestDialogController::sendSelectAccountResponse(const QString &account)
+{
+ d_ptr->sendSelectAccountResponse(account);
+}
+
+void AuthenticatorRequestDialogController::finishCollectToken()
+{
+ d_ptr->finishCollectToken();
+}
+
+void AuthenticatorRequestDialogController::finishRequest()
+{
+ d_ptr->finishRequest();
+}
+
+QWebEngineWebAuthUxRequest::WebAuthUxState AuthenticatorRequestDialogController::state() const
+{
+ return d_ptr->state();
+}
+
+void AuthenticatorRequestDialogController::startRequest(bool bIsConditionalRequest)
+{
+ d_ptr->startRequest(bIsConditionalRequest);
+}
+
+void AuthenticatorRequestDialogController::setRelyingPartyId(const std::string &rpId)
+{
+ d_ptr->setRelyingPartyId(QString::fromStdString(rpId));
+}
+
+QString AuthenticatorRequestDialogController::relyingPartyId() const
+{
+ return d_ptr->relyingPartyId();
+}
+
+void AuthenticatorRequestDialogController::handleRequestFailure(
+ QWebEngineWebAuthUxRequest::RequestFailureReason reason)
+{
+ d_ptr->handleRequestFailure(reason);
+}
+
+void AuthenticatorRequestDialogController::retryRequest()
+{
+ d_ptr->retryRequest();
+}
+
+void AuthenticatorRequestDialogController::sendCollectPinResponse(const QString &pin)
+{
+ d_ptr->sendCollectPinResponse(pin);
+}
+
+QWebEngineWebAuthUxRequest::RequestFailureReason
+AuthenticatorRequestDialogController::requestFailureReason() const
+{
+ return d_ptr->requestFailureReason();
+}
+}
diff --git a/src/core/authenticator_request_dialog_controller.h b/src/core/authenticator_request_dialog_controller.h
new file mode 100644
index 000000000..98e8dcf90
--- /dev/null
+++ b/src/core/authenticator_request_dialog_controller.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef AUTHENTICATOR_REQUEST_DIALOG_CONTROLLER_H
+#define AUTHENTICATOR_REQUEST_DIALOG_CONTROLLER_H
+
+#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+#include <QtCore/qobject.h>
+#include "qwebenginewebauthuxrequest.h"
+
+namespace content {
+class WebContents;
+class RenderFrameHost;
+}
+namespace QtWebEngineCore {
+
+class AuthenticatorRequestDialogControllerPrivate;
+
+class Q_WEBENGINECORE_EXPORT AuthenticatorRequestDialogController : public QObject
+{
+ Q_OBJECT
+public:
+ ~AuthenticatorRequestDialogController();
+ void sendSelectAccountResponse(const QString &account);
+ void sendCollectPinResponse(const QString &pin);
+ QStringList userNames() const;
+ QWebEngineWebAuthPinRequest pinRequest();
+ void reject();
+ AuthenticatorRequestDialogController(AuthenticatorRequestDialogControllerPrivate *);
+
+ QWebEngineWebAuthUxRequest::WebAuthUxState state() const;
+ QString relyingPartyId() const;
+ void retryRequest();
+ QWebEngineWebAuthUxRequest::RequestFailureReason requestFailureReason() const;
+
+Q_SIGNALS:
+ void stateChanged(QWebEngineWebAuthUxRequest::WebAuthUxState state);
+
+private:
+ void selectAccount(const QStringList &userList);
+ void collectPin(QWebEngineWebAuthPinRequest pinRequest);
+ void finishCollectToken();
+ void startRequest(bool bIsConditionalRequest);
+ void finishRequest();
+ void setRelyingPartyId(const std::string &rpId);
+ void handleRequestFailure(QWebEngineWebAuthUxRequest::RequestFailureReason reason);
+
+ QScopedPointer<AuthenticatorRequestDialogControllerPrivate> d_ptr;
+ friend class AuthenticatorRequestClientDelegateQt;
+};
+}
+
+#endif // AUTHENTICATOR_REQUEST_DIALOG_CONTROLLER_H
diff --git a/src/core/authenticator_request_dialog_controller_p.h b/src/core/authenticator_request_dialog_controller_p.h
new file mode 100644
index 000000000..5e7333d56
--- /dev/null
+++ b/src/core/authenticator_request_dialog_controller_p.h
@@ -0,0 +1,78 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef AUTHENTICATOR_REQUEST_DIALOG_CONTROLLER_P_H
+#define AUTHENTICATOR_REQUEST_DIALOG_CONTROLLER_P_H
+#include <QStringList>
+#include <QSharedPointer>
+#include "authenticator_request_client_delegate_qt.h"
+#include "authenticator_request_dialog_controller.h"
+
+namespace content {
+class WebContents;
+class RenderFrameHost;
+}
+
+namespace QtWebEngineCore {
+
+class AuthenticatorRequestDialogControllerPrivate
+{
+
+public:
+ AuthenticatorRequestDialogControllerPrivate(
+ content::RenderFrameHost *renderFrameHost,
+ base::WeakPtr<AuthenticatorRequestClientDelegateQt> authenticatorRequestDelegate);
+ ~AuthenticatorRequestDialogControllerPrivate();
+ void showWebAuthDialog();
+ void selectAccount(const QStringList &userList);
+ QStringList userNames() const;
+ QString relyingPartyId() const;
+ QWebEngineWebAuthUxRequest::WebAuthUxState state() const;
+ QWebEngineWebAuthPinRequest pinRequest();
+ QWebEngineWebAuthUxRequest::RequestFailureReason requestFailureReason() const;
+ void sendSelectAccountResponse(const QString &selectedAccount);
+ void setCurrentState(QWebEngineWebAuthUxRequest::WebAuthUxState uxState);
+ void setRelyingPartyId(const QString &rpId);
+
+ // Support pin functionality
+ void collectPin(QWebEngineWebAuthPinRequest pinRequestInfo);
+ void finishCollectToken();
+ void handleRequestFailure(QWebEngineWebAuthUxRequest::RequestFailureReason reason);
+ void sendCollectPinResponse(const QString &pin);
+
+ // Deleting dialog;
+ void finishRequest();
+
+ // cancel request
+ void cancelRequest();
+ void retryRequest();
+ void startRequest(bool isConditionalRequest);
+
+ AuthenticatorRequestDialogController *q_ptr;
+
+private:
+ content::RenderFrameHost *m_renderFrameHost;
+ QStringList m_userList;
+ QString m_pin;
+ QString m_relyingPartyId;
+
+ bool m_isStarted = false;
+ bool m_isConditionalRequest = false;
+ QWebEngineWebAuthUxRequest::WebAuthUxState m_currentState =
+ QWebEngineWebAuthUxRequest::WebAuthUxState::NotStarted;
+ base::WeakPtr<AuthenticatorRequestClientDelegateQt> m_authenticatorRequestDelegate;
+ bool m_isDialogCreated = false;
+ QWebEngineWebAuthPinRequest m_pinRequest;
+
+ QWebEngineWebAuthUxRequest *m_request = nullptr;
+ QWebEngineWebAuthUxRequest::RequestFailureReason m_requestFailureReason;
+
+ // m_pendingState holds requested steps until the UI is shown. The UI is only
+ // shown once the TransportAvailabilityInfo is available, but authenticators
+ // may request, e.g., PIN entry prior to that.
+ absl::optional<QWebEngineWebAuthUxRequest::WebAuthUxState> m_pendingState;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // AUTHENTICATOR_REQUEST_DIALOG_CONTROLLER_P_H
diff --git a/src/core/autofill_client_qt.cpp b/src/core/autofill_client_qt.cpp
index aaf775d60..3bdc62e19 100644
--- a/src/core/autofill_client_qt.cpp
+++ b/src/core/autofill_client_qt.cpp
@@ -10,16 +10,23 @@
#include "web_contents_adapter_client.h"
#include "web_contents_view_qt.h"
-#include "base/task/thread_pool.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "chrome/browser/profiles/profile.h"
#include "components/autofill/core/common/autofill_prefs.h"
#include "content/browser/web_contents/web_contents_impl.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
namespace QtWebEngineCore {
+void AutofillClientQt::CreateForWebContents(content::WebContents *contents)
+{
+ DCHECK(contents);
+ if (!FromWebContents(contents))
+ contents->SetUserData(UserDataKey(), base::WrapUnique(new AutofillClientQt(contents)));
+}
+
AutofillClientQt::AutofillClientQt(content::WebContents *webContents)
- : content::WebContentsUserData<AutofillClientQt>(*webContents)
+ : autofill::ContentAutofillClient(
+ webContents, base::BindRepeating(&autofill::BrowserDriverInitHook, this, ""))
, content::WebContentsObserver(webContents)
, m_popupController(new AutofillPopupController(new AutofillPopupControllerPrivate))
{
@@ -51,16 +58,16 @@ const PrefService *AutofillClientQt::GetPrefs() const
void AutofillClientQt::ShowAutofillPopup(const autofill::AutofillClient::PopupOpenArgs &open_args,
base::WeakPtr<autofill::AutofillPopupDelegate> delegate)
{
- // Specific popups (personal, address, credit card, password) are not supported.
- DCHECK(open_args.popup_type == autofill::PopupType::kUnspecified);
-
m_popupController->d->delegate = delegate;
m_popupController->d->suggestions = open_args.suggestions;
m_popupController->updateModel();
+ bool autoSelectFirstSuggestion =
+ open_args.trigger_source == autofill::AutofillSuggestionTriggerSource::kTextFieldDidReceiveKeyDown;
+
adapterClient()->showAutofillPopup(m_popupController.data(),
QRect(toQt(gfx::ToEnclosingRect(open_args.element_bounds))),
- open_args.autoselect_first_suggestion.value());
+ autoSelectFirstSuggestion);
}
void AutofillClientQt::UpdateAutofillPopupDataListValues(const std::vector<std::u16string> &values,
@@ -78,21 +85,21 @@ void AutofillClientQt::PinPopupView()
NOTIMPLEMENTED();
}
-autofill::AutofillClient::PopupOpenArgs AutofillClientQt::GetReopenPopupArgs() const
+autofill::AutofillClient::PopupOpenArgs AutofillClientQt::GetReopenPopupArgs(autofill::AutofillSuggestionTriggerSource trigger_source) const
{
// Called by password_manager component only.
NOTIMPLEMENTED();
return autofill::AutofillClient::PopupOpenArgs();
}
-base::span<const autofill::Suggestion> AutofillClientQt::GetPopupSuggestions() const
+std::vector<autofill::Suggestion> AutofillClientQt::GetPopupSuggestions() const
{
// Called by password_manager component only.
NOTIMPLEMENTED();
- return base::span<const autofill::Suggestion>();
+ return {};
}
-void AutofillClientQt::UpdatePopup(const std::vector<autofill::Suggestion> &, autofill::PopupType)
+void AutofillClientQt::UpdatePopup(const std::vector<autofill::Suggestion> &, autofill::PopupType, autofill::AutofillSuggestionTriggerSource)
{
// Called by password_manager component only.
NOTIMPLEMENTED();
@@ -103,7 +110,7 @@ void AutofillClientQt::HideAutofillPopup(autofill::PopupHidingReason)
adapterClient()->hideAutofillPopup();
}
-bool AutofillClientQt::IsAutocompleteEnabled()
+bool AutofillClientQt::IsAutocompleteEnabled() const
{
return autofill::prefs::IsAutocompleteEnabled(GetPrefs());
}
@@ -113,8 +120,18 @@ bool AutofillClientQt::IsPasswordManagerEnabled()
return false;
}
-void AutofillClientQt::PropagateAutofillPredictions(autofill::AutofillDriver *,
- const std::vector<autofill::FormStructure *> &)
+bool AutofillClientQt::IsOffTheRecord()
+{
+ return web_contents()->GetBrowserContext()->IsOffTheRecord();
+}
+
+scoped_refptr<network::SharedURLLoaderFactory> AutofillClientQt::GetURLLoaderFactory()
+{
+ return nullptr;
+}
+
+void AutofillClientQt::PropagateAutofillPredictionsDeprecated(autofill::AutofillDriver *,
+ const std::vector<autofill::FormStructure *> &)
{
// For testing purposes only.
NOTIMPLEMENTED();
@@ -127,6 +144,4 @@ WebContentsAdapterClient *AutofillClientQt::adapterClient()
->client();
}
-WEB_CONTENTS_USER_DATA_KEY_IMPL(AutofillClientQt);
-
} // namespace QtWebEngineCore
diff --git a/src/core/autofill_client_qt.h b/src/core/autofill_client_qt.h
index 95ae460f2..cd38de462 100644
--- a/src/core/autofill_client_qt.h
+++ b/src/core/autofill_client_qt.h
@@ -19,7 +19,7 @@
#include <vector>
#include "base/memory/weak_ptr.h"
-#include "components/autofill/core/browser/autofill_client.h"
+#include "components/autofill/content/browser/content_autofill_client.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/browser/web_contents_user_data.h"
@@ -30,13 +30,14 @@ namespace QtWebEngineCore {
class AutofillPopupController;
class WebContentsAdapterClient;
-class AutofillClientQt : public autofill::AutofillClient,
- public content::WebContentsUserData<AutofillClientQt>,
+class AutofillClientQt : public autofill::ContentAutofillClient,
public content::WebContentsObserver
{
public:
~AutofillClientQt() override;
+ static void CreateForWebContents(content::WebContents *contents);
+
// autofill::AutofillClient overrides:
autofill::PersonalDataManager *GetPersonalDataManager() override;
autofill::AutocompleteHistoryManager *GetAutocompleteHistoryManager() override;
@@ -48,15 +49,19 @@ public:
void UpdateAutofillPopupDataListValues(const std::vector<std::u16string> &values,
const std::vector<std::u16string> &labels) override;
void PinPopupView() override;
- autofill::AutofillClient::PopupOpenArgs GetReopenPopupArgs() const override;
- base::span<const autofill::Suggestion> GetPopupSuggestions() const override;
- void UpdatePopup(const std::vector<autofill::Suggestion> &, autofill::PopupType) override;
+ PopupOpenArgs GetReopenPopupArgs(
+ autofill::AutofillSuggestionTriggerSource trigger_source) const override;
+ std::vector<autofill::Suggestion> GetPopupSuggestions() const override;
+ void UpdatePopup(const std::vector<autofill::Suggestion>& suggestions,
+ autofill::PopupType popup_type,
+ autofill::AutofillSuggestionTriggerSource trigger_source) override;
void HideAutofillPopup(autofill::PopupHidingReason reason) override;
- bool IsAutocompleteEnabled() override;
+ bool IsAutocompleteEnabled() const override;
bool IsPasswordManagerEnabled() override;
- void PropagateAutofillPredictions(autofill::AutofillDriver *,
- const std::vector<autofill::FormStructure *> &) override;
-
+ void PropagateAutofillPredictionsDeprecated(autofill::AutofillDriver *,
+ const std::vector<autofill::FormStructure *> &) override;
+ bool IsOffTheRecord() override;
+ scoped_refptr<network::SharedURLLoaderFactory> GetURLLoaderFactory() override;
private:
explicit AutofillClientQt(content::WebContents *webContents);
@@ -64,9 +69,6 @@ private:
WebContentsAdapterClient *adapterClient();
QScopedPointer<AutofillPopupController> m_popupController;
-
- WEB_CONTENTS_USER_DATA_KEY_DECL();
- friend class content::WebContentsUserData<AutofillClientQt>;
};
} // namespace QtWebEngineCore
diff --git a/src/core/autofill_popup_controller.cpp b/src/core/autofill_popup_controller.cpp
index 6e5890e47..a6baf5fc2 100644
--- a/src/core/autofill_popup_controller.cpp
+++ b/src/core/autofill_popup_controller.cpp
@@ -26,7 +26,7 @@ void AutofillPopupController::setCurrentIndex(const QModelIndex &index)
if (m_currentIndex.isValid()) {
const autofill::Suggestion &suggestion = d->suggestions[m_currentIndex.row()];
- d->delegate->DidSelectSuggestion(suggestion.main_text.value, suggestion.frontend_id, autofill::Suggestion::BackendId());
+ d->delegate->DidSelectSuggestion(suggestion, autofill::AutofillSuggestionTriggerSource::kFormControlElementClicked);
}
Q_EMIT currentIndexChanged(index);
@@ -79,7 +79,7 @@ void AutofillPopupController::acceptSuggestion()
const int index = m_currentIndex.row();
const autofill::Suggestion &suggestion = d->suggestions[index];
- d->delegate->DidAcceptSuggestion(suggestion, index);
+ d->delegate->DidAcceptSuggestion(suggestion, index, autofill::AutofillSuggestionTriggerSource::kFormControlElementClicked);
}
void AutofillPopupController::notifyPopupShown()
diff --git a/src/core/autofill_popup_controller.h b/src/core/autofill_popup_controller.h
index 586149b95..1b4d8d7e8 100644
--- a/src/core/autofill_popup_controller.h
+++ b/src/core/autofill_popup_controller.h
@@ -15,7 +15,7 @@ namespace QtWebEngineCore {
class AutofillPopupControllerPrivate;
-class Q_WEBENGINECORE_PRIVATE_EXPORT AutofillPopupController : public QObject
+class Q_WEBENGINECORE_EXPORT AutofillPopupController : public QObject
{
Q_OBJECT
Q_PROPERTY(QStringListModel *model READ model CONSTANT FINAL)
diff --git a/src/core/browser_accessibility_manager_qt.cpp b/src/core/browser_accessibility_manager_qt.cpp
index f89110036..077856266 100644
--- a/src/core/browser_accessibility_manager_qt.cpp
+++ b/src/core/browser_accessibility_manager_qt.cpp
@@ -13,10 +13,6 @@
#include "render_widget_host_view_qt.h" // WebContentsAccessibilityQt
#include "content/browser/accessibility/browser_accessibility.h"
-#if QT_CONFIG(webengine_extensions)
-#include "content/browser/renderer_host/render_frame_host_impl.h"
-#include "content/public/browser/web_contents.h"
-#endif // QT_CONFIG(webengine_extensions)
#include "ui/accessibility/ax_enums.mojom.h"
#include <QtGui/qaccessible.h>
@@ -34,15 +30,10 @@ BrowserAccessibilityManager *BrowserAccessibilityManager::Create(
QtWebEngineCore::WebContentsAccessibilityQt *access = nullptr;
access = static_cast<QtWebEngineCore::WebContentsAccessibilityQt *>(delegate->AccessibilityGetWebContentsAccessibility());
-#if QT_CONFIG(webengine_extensions)
- // Accessibility is not supported for guest views.
+ // Accessibility is not supported for guest views and child frames.
if (!access) {
- Q_ASSERT(content::WebContents::FromRenderFrameHost(
- static_cast<content::RenderFrameHostImpl *>(delegate))
- ->GetOuterWebContents());
return nullptr;
}
-#endif // QT_CONFIG(webengine_extensions)
return new BrowserAccessibilityManagerQt(access, initialTree, delegate);
#else
@@ -83,7 +74,7 @@ BrowserAccessibilityManagerQt::~BrowserAccessibilityManagerQt()
QAccessibleInterface *BrowserAccessibilityManagerQt::rootParentAccessible()
{
- content::BrowserAccessibility *parent_node = GetParentNodeFromParentTree();
+ content::BrowserAccessibility *parent_node = GetParentNodeFromParentTreeAsBrowserAccessibility();
if (!parent_node) {
Q_ASSERT(m_webContentsAccessibility);
return QAccessible::queryAccessibleInterface(m_webContentsAccessibility->accessibilityParentObject());
@@ -103,6 +94,8 @@ void BrowserAccessibilityManagerQt::FireBlinkEvent(ax::mojom::Event event_type,
switch (event_type) {
case ax::mojom::Event::kFocus: {
QAccessibleEvent event(iface, QAccessible::Focus);
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
break;
}
@@ -110,6 +103,8 @@ void BrowserAccessibilityManagerQt::FireBlinkEvent(ax::mojom::Event event_type,
QAccessible::State change;
change.checked = true;
QAccessibleStateChangeEvent event(iface, change);
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
break;
}
@@ -118,6 +113,8 @@ void BrowserAccessibilityManagerQt::FireBlinkEvent(ax::mojom::Event event_type,
if (QAccessibleValueInterface *valueIface = iface->valueInterface())
value = valueIface->currentValue();
QAccessibleValueChangeEvent event(iface, value);
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
break;
}
@@ -129,6 +126,8 @@ void BrowserAccessibilityManagerQt::FireBlinkEvent(ax::mojom::Event event_type,
break;
case ax::mojom::Event::kTextChanged: {
QAccessibleTextUpdateEvent event(iface, -1, QString(), QString());
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
break;
}
@@ -140,9 +139,13 @@ void BrowserAccessibilityManagerQt::FireBlinkEvent(ax::mojom::Event event_type,
textIface->selection(0, &start, &end);
if (start == end) {
QAccessibleTextCursorEvent event(iface, start);
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
} else {
QAccessibleTextSelectionEvent event(iface, start, end);
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
}
}
@@ -166,6 +169,8 @@ void BrowserAccessibilityManagerQt::FireGeneratedEvent(ui::AXEventGenerator::Eve
case ui::AXEventGenerator::Event::VALUE_IN_TEXT_FIELD_CHANGED:
if (iface->role() == QAccessible::EditableText) {
QAccessibleTextUpdateEvent event(iface, -1, QString(), QString());
+ if (event.object())
+ event.setChild(-1);
QAccessible::updateAccessibility(&event);
}
break;
diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp
index 844d77492..de3347df3 100644
--- a/src/core/browser_accessibility_qt.cpp
+++ b/src/core/browser_accessibility_qt.cpp
@@ -10,6 +10,7 @@
#include "qtwebenginecoreglobal_p.h"
#include "type_conversion.h"
+#if QT_CONFIG(accessibility)
#include "content/browser/accessibility/browser_accessibility.h"
#include "ui/accessibility/ax_enums.mojom.h"
@@ -25,10 +26,9 @@ public:
BrowserAccessibilityQt(content::BrowserAccessibilityManager *manager, ui::AXNode *node);
~BrowserAccessibilityQt();
- QtWebEngineCore::BrowserAccessibilityInterface *interface() const { return m_interface; }
+ bool isReady() const;
-private:
- QtWebEngineCore::BrowserAccessibilityInterface *m_interface = nullptr;
+ QtWebEngineCore::BrowserAccessibilityInterface *interface = nullptr;
};
class BrowserAccessibilityInterface
@@ -41,6 +41,7 @@ class BrowserAccessibilityInterface
{
public:
BrowserAccessibilityInterface(BrowserAccessibilityQt *chromiumInterface);
+ ~BrowserAccessibilityInterface() override;
void destroy();
@@ -126,20 +127,31 @@ public:
void modelChange(QAccessibleTableModelChangeEvent *event) override;
private:
+ content::BrowserAccessibility *findTable() const;
+
QObject *m_object = nullptr;
QAccessible::Id m_id = 0;
BrowserAccessibilityQt *q;
};
-BrowserAccessibilityQt::BrowserAccessibilityQt(content::BrowserAccessibilityManager *manager, ui::AXNode *node)
- : content::BrowserAccessibility(manager, node),
- m_interface(new BrowserAccessibilityInterface(this))
+BrowserAccessibilityQt::BrowserAccessibilityQt(content::BrowserAccessibilityManager *manager,
+ ui::AXNode *node)
+ : content::BrowserAccessibility(manager, node)
+ , interface(new BrowserAccessibilityInterface(this))
{
}
BrowserAccessibilityQt::~BrowserAccessibilityQt()
{
- m_interface->destroy();
+ if (interface)
+ interface->destroy();
+}
+
+bool BrowserAccessibilityQt::isReady() const
+{
+ // FIXME: This is just a workaround, remove this when the commented out assert in
+ // BrowserAccessibilityManager::GetFromID(int32_t id) gets fixed.
+ return manager()->GetFromID(node()->id()) != nullptr;
}
BrowserAccessibilityInterface::BrowserAccessibilityInterface(BrowserAccessibilityQt *chromiumInterface)
@@ -155,6 +167,11 @@ BrowserAccessibilityInterface::BrowserAccessibilityInterface(BrowserAccessibilit
m_id = QAccessible::registerAccessibleInterface(this);
}
+BrowserAccessibilityInterface::~BrowserAccessibilityInterface()
+{
+ q->interface = nullptr;
+}
+
void BrowserAccessibilityInterface::destroy()
{
QAccessible::deleteAccessibleInterface(m_id);
@@ -162,6 +179,9 @@ void BrowserAccessibilityInterface::destroy()
bool BrowserAccessibilityInterface::isValid() const
{
+ if (!q->isReady())
+ return false;
+
auto managerQt = static_cast<content::BrowserAccessibilityManagerQt *>(q->manager());
return managerQt && managerQt->isValid();
}
@@ -212,10 +232,10 @@ void *BrowserAccessibilityInterface::interface_cast(QAccessible::InterfaceType t
}
case QAccessible::TableCellInterface: {
QAccessible::Role r = role();
- if (r == QAccessible::Cell ||
- r == QAccessible::ListItem ||
- r == QAccessible::TreeItem)
- return static_cast<QAccessibleTableCellInterface*>(this);
+ if (r == QAccessible::Cell || r == QAccessible::ListItem || r == QAccessible::TreeItem) {
+ if (findTable())
+ return static_cast<QAccessibleTableCellInterface *>(this);
+ }
break;
}
default:
@@ -265,6 +285,9 @@ int BrowserAccessibilityInterface::indexOfChild(const QAccessibleInterface *ifac
QString BrowserAccessibilityInterface::text(QAccessible::Text t) const
{
+ if (!q->isReady())
+ return QString();
+
switch (t) {
case QAccessible::Name:
return toQt(q->GetStringAttribute(ax::mojom::StringAttribute::kName));
@@ -286,7 +309,7 @@ void BrowserAccessibilityInterface::setText(QAccessible::Text t, const QString &
QRect BrowserAccessibilityInterface::rect() const
{
- if (!q->manager()) // needed implicitly by GetScreenBoundsRect()
+ if (!q->manager() || !q->isReady()) // needed implicitly by GetScreenBoundsRect()
return QRect();
gfx::Rect bounds = q->GetUnclippedScreenBoundsRect();
bounds = gfx::ScaleToRoundedRect(bounds, 1.f / q->manager()->device_scale_factor()); // FIXME: check
@@ -688,6 +711,11 @@ QAccessible::Role BrowserAccessibilityInterface::role() const
QAccessible::State BrowserAccessibilityInterface::state() const
{
QAccessible::State state = QAccessible::State();
+ if (!q->isReady()) {
+ state.invalid = true;
+ return state;
+ }
+
if (q->HasState(ax::mojom::State::kCollapsed))
state.collapsed = true;
if (q->HasState(ax::mojom::State::kDefault))
@@ -1102,14 +1130,20 @@ bool BrowserAccessibilityInterface::isSelected() const
return false;
}
+content::BrowserAccessibility *BrowserAccessibilityInterface::findTable() const
+{
+ content::BrowserAccessibility *parent = q->PlatformGetParent();
+ while (parent && parent->GetRole() != ax::mojom::Role::kTable)
+ parent = parent->PlatformGetParent();
+
+ return parent;
+}
+
QAccessibleInterface *BrowserAccessibilityInterface::table() const
{
- content::BrowserAccessibility *find_table = q->PlatformGetParent();
- while (find_table && find_table->GetRole() != ax::mojom::Role::kTable)
- find_table = find_table->PlatformGetParent();
- if (!find_table)
- return nullptr;
- return content::toQAccessibleInterface(find_table);
+ content::BrowserAccessibility *table = findTable();
+ Q_ASSERT(table);
+ return content::toQAccessibleInterface(table);
}
void BrowserAccessibilityInterface::modelChange(QAccessibleTableModelChangeEvent *)
@@ -1118,22 +1152,31 @@ void BrowserAccessibilityInterface::modelChange(QAccessibleTableModelChangeEvent
} // namespace QtWebEngineCore
+#endif // QT_CONFIG(accessibility)
namespace content {
// static
std::unique_ptr<BrowserAccessibility> BrowserAccessibility::Create(BrowserAccessibilityManager *man, ui::AXNode *node)
{
+#if QT_CONFIG(accessibility)
return std::unique_ptr<BrowserAccessibility>(new QtWebEngineCore::BrowserAccessibilityQt(man, node));
+#else
+ Q_UNUSED(man);
+ Q_UNUSED(node);
+ return nullptr;
+#endif // #if QT_CONFIG(accessibility)
}
+#if QT_CONFIG(accessibility)
QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *obj)
{
- return static_cast<QtWebEngineCore::BrowserAccessibilityQt *>(obj)->interface();
+ return static_cast<QtWebEngineCore::BrowserAccessibilityQt *>(obj)->interface;
}
const QAccessibleInterface *toQAccessibleInterface(const BrowserAccessibility *obj)
{
- return static_cast<const QtWebEngineCore::BrowserAccessibilityQt *>(obj)->interface();
+ return static_cast<const QtWebEngineCore::BrowserAccessibilityQt *>(obj)->interface;
}
+#endif // #if QT_CONFIG(accessibility)
} // namespace content
diff --git a/src/core/browser_accessibility_qt.h b/src/core/browser_accessibility_qt.h
index 455478247..598aa3ef5 100644
--- a/src/core/browser_accessibility_qt.h
+++ b/src/core/browser_accessibility_qt.h
@@ -4,8 +4,9 @@
#ifndef BROWSER_ACCESSIBILITY_QT_H
#define BROWSER_ACCESSIBILITY_QT_H
-#include <QtCore/qtconfigmacros.h>
+#include <QtGui/qtguiglobal.h>
+#if QT_CONFIG(accessibility)
QT_FORWARD_DECLARE_CLASS(QAccessibleInterface)
namespace content {
@@ -15,5 +16,6 @@ QAccessibleInterface *toQAccessibleInterface(BrowserAccessibility *obj);
const QAccessibleInterface *toQAccessibleInterface(const BrowserAccessibility *obj);
} // namespace content
+#endif // QT_CONFIG(accessibility)
#endif // BROWSER_ACCESSIBILITY_QT_H
diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp
index e58822c29..9021dbb98 100644
--- a/src/core/browser_main_parts_qt.cpp
+++ b/src/core/browser_main_parts_qt.cpp
@@ -50,6 +50,7 @@
#include "web_engine_context.h"
#include "web_usb_detector_qt.h"
+#include <QDeadlineTimer>
#include <QtGui/qtgui-config.h>
#include <QStandardPaths>
@@ -59,8 +60,9 @@
#endif
#if BUILDFLAG(IS_MAC)
-#include "base/message_loop/message_pump_mac.h"
+#include "base/message_loop/message_pump_apple.h"
#include "services/device/public/cpp/geolocation/geolocation_manager.h"
+#include "services/device/public/cpp/geolocation/system_geolocation_source.h"
#include "ui/base/idle/idle.h"
#endif
@@ -71,8 +73,8 @@
#endif
#if defined(Q_OS_LINUX)
-#include "components/os_crypt/key_storage_config_linux.h"
-#include "components/os_crypt/os_crypt.h"
+#include "components/os_crypt/sync/key_storage_config_linux.h"
+#include "components/os_crypt/sync/os_crypt.h"
#endif
namespace QtWebEngineCore {
@@ -120,7 +122,7 @@ public:
{
// NOTE: This method may called from any thread at any time.
ensureDelegate();
- m_scheduler.scheduleWork();
+ m_scheduler.scheduleImmediateWork();
}
void ScheduleDelayedWork(const Delegate::NextWorkInfo &next_work_info) override
@@ -144,62 +146,19 @@ private:
seqMan->controller_.get());
}
}
- // Both Qt and Chromium keep track of the current GL context by using
- // thread-local variables, and naturally they are completely unaware of each
- // other. As a result, when a QOpenGLContext is made current, the previous
- // gl::GLContext is not released, and vice-versa. This is fine as long as
- // each thread uses exclusively either Qt or Chromium GL bindings, which is
- // usually the case.
- //
- // The only exception is when the GL driver is considered thread-unsafe
- // (QOpenGLContext::supportsThreadedOpenGL() is false), in which case we
- // have to run all GL operations, including Chromium's GPU service, on the
- // UI thread. Now the bindings are being mixed and both Qt and Chromium get
- // quite confused regarding the current state of the surface.
- //
- // To get this to work we have to release the current QOpenGLContext before
- // executing any tasks from Chromium's GPU service and the gl::GLContext
- // afterwards. Since GPU service just posts tasks to the UI thread task
- // runner, we'll have to instrument the entire UI thread message pump.
- class ScopedGLContextChecker
- {
-#if QT_CONFIG(opengl)
- public:
- ScopedGLContextChecker()
- {
- if (!m_enabled)
- return;
-
- if (QOpenGLContext *context = QOpenGLContext::currentContext())
- context->doneCurrent();
- }
-
- ~ScopedGLContextChecker()
- {
- if (!m_enabled)
- return;
-
- if (gl::GLContext *context = gl::GLContext::GetCurrent())
- context->ReleaseCurrent(nullptr);
- }
-
- private:
- bool m_enabled = WebEngineContext::isGpuServiceOnUIThread();
-#endif // QT_CONFIG(opengl)
- };
-
void handleScheduledWork()
{
- ScopedGLContextChecker glContextChecker;
-
+ QDeadlineTimer timer(std::chrono::milliseconds(2));
base::MessagePump::Delegate::NextWorkInfo more_work_info = m_delegate->DoWork();
+ while (more_work_info.is_immediate() && !timer.hasExpired())
+ more_work_info = m_delegate->DoWork();
if (more_work_info.is_immediate())
- return ScheduleWork();
+ return m_scheduler.scheduleImmediateWork();
if (m_delegate->DoIdleWork())
- return ScheduleWork();
+ return m_scheduler.scheduleIdleWork();
ScheduleDelayedWork(more_work_info.delayed_run_time);
}
@@ -209,19 +168,21 @@ private:
};
#if BUILDFLAG(IS_MAC)
-class FakeGeolocationManager : public device::GeolocationManager
+class FakeGeolocationSource : public device::SystemGeolocationSource
{
public:
- FakeGeolocationManager() = default;
- ~FakeGeolocationManager() override = default;
+ FakeGeolocationSource() = default;
+ ~FakeGeolocationSource() override = default;
- // GeolocationManager implementation:
+ // SystemGeolocationSource implementation:
void StartWatchingPosition(bool) override {}
void StopWatchingPosition() override {}
- device::LocationSystemPermissionStatus GetSystemPermission() const override
+ void RegisterPermissionUpdateCallback(PermissionUpdateCallback callback)
{
- return device::LocationSystemPermissionStatus::kDenied;
+ callback.Run(device::LocationSystemPermissionStatus::kDenied);
}
+ void RegisterPositionUpdateCallback(PositionUpdateCallback callback) {}
+ void RequestPermission() override {}
};
#endif // BUILDFLAG(IS_MAC)
@@ -233,7 +194,7 @@ std::unique_ptr<base::MessagePump> messagePumpFactory()
return std::make_unique<MessagePumpForUIQt>();
}
#if BUILDFLAG(IS_MAC)
- return base::MessagePumpMac::Create();
+ return base::message_pump_apple::Create();
#else
return std::make_unique<base::MessagePumpForUI>();
#endif
@@ -250,7 +211,7 @@ int BrowserMainPartsQt::PreEarlyInitialization()
void BrowserMainPartsQt::PreCreateMainMessageLoop()
{
#if BUILDFLAG(IS_MAC)
- m_geolocationManager = std::make_unique<FakeGeolocationManager>();
+ m_geolocationManager = std::make_unique<device::GeolocationManager>(std::make_unique<FakeGeolocationSource>());
#endif
}
@@ -260,9 +221,8 @@ void BrowserMainPartsQt::PostCreateMainMessageLoop()
device_event_log::Initialize(0 /* default max entries */);
#if defined(Q_OS_LINUX)
- std::unique_ptr<os_crypt::Config> config = std::make_unique<os_crypt::Config>();
+ auto config = std::make_unique<os_crypt::Config>();
config->product_name = "Qt WebEngine";
- config->main_thread_runner = content::GetUIThreadTaskRunner({});
config->should_use_preference = false;
config->user_data_path = toFilePath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation));
OSCrypt::SetConfig(std::move(config));
@@ -271,7 +231,7 @@ void BrowserMainPartsQt::PostCreateMainMessageLoop()
int BrowserMainPartsQt::PreMainMessageLoopRun()
{
- ui::SelectFileDialog::SetFactory(new SelectFileDialogFactoryQt());
+ ui::SelectFileDialog::SetFactory(std::make_unique<SelectFileDialogFactoryQt>());
#if BUILDFLAG(ENABLE_EXTENSIONS)
extensions::ExtensionsClient::Set(new extensions::ExtensionsClientQt());
diff --git a/src/core/browser_message_filter_qt.h b/src/core/browser_message_filter_qt.h
index 53c48eb6e..0f5721c82 100644
--- a/src/core/browser_message_filter_qt.h
+++ b/src/core/browser_message_filter_qt.h
@@ -4,7 +4,7 @@
#ifndef BROWSER_MESSAGE_FILTER_QT_H
#define BROWSER_MESSAGE_FILTER_QT_H
-#include "base/callback.h"
+#include "base/functional/callback.h"
#include "content/public/browser/browser_message_filter.h"
class GURL;
diff --git a/src/core/browsing_data_remover_delegate_qt.cpp b/src/core/browsing_data_remover_delegate_qt.cpp
index bbfd902ec..eb33fb992 100644
--- a/src/core/browsing_data_remover_delegate_qt.cpp
+++ b/src/core/browsing_data_remover_delegate_qt.cpp
@@ -3,8 +3,8 @@
#include "browsing_data_remover_delegate_qt.h"
-#include "base/bind.h"
-#include "base/callback.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback.h"
#include "components/web_cache/browser/web_cache_manager.h"
#include "content/public/browser/browsing_data_remover.h"
@@ -50,7 +50,8 @@ void BrowsingDataRemoverDelegateQt::RemoveEmbedderData(const base::Time &delete_
std::move(callback).Run(0);
}
-std::vector<std::string> BrowsingDataRemoverDelegateQt::GetDomainsForDeferredCookieDeletion(uint64_t)
+std::vector<std::string> BrowsingDataRemoverDelegateQt::GetDomainsForDeferredCookieDeletion(
+ content::StoragePartition *, uint64_t)
{
return {};
}
diff --git a/src/core/browsing_data_remover_delegate_qt.h b/src/core/browsing_data_remover_delegate_qt.h
index 4e690ffb1..d33af4acb 100644
--- a/src/core/browsing_data_remover_delegate_qt.h
+++ b/src/core/browsing_data_remover_delegate_qt.h
@@ -4,6 +4,8 @@
#ifndef BROWSING_DATA_REMOVER_DELEGATE_QT_H
#define BROWSING_DATA_REMOVER_DELEGATE_QT_H
+#include <cstdint>
+
#include "content/public/browser/browsing_data_remover_delegate.h"
namespace QtWebEngineCore {
@@ -17,13 +19,15 @@ public:
content::BrowsingDataRemoverDelegate::EmbedderOriginTypeMatcher GetOriginTypeMatcher() override;
bool MayRemoveDownloadHistory() override;
void RemoveEmbedderData(
- const base::Time &delete_begin,
- const base::Time &delete_end,
- uint64_t remove_mask,
- content::BrowsingDataFilterBuilder *filter_builder,
- uint64_t origin_type_mask,
- base::OnceCallback<void(/*failed_data_types=*/uint64_t)> callback) override;
- std::vector<std::string> GetDomainsForDeferredCookieDeletion(uint64_t) override;
+ const base::Time &delete_begin,
+ const base::Time &delete_end,
+ uint64_t remove_mask,
+ content::BrowsingDataFilterBuilder *filter_builder,
+ uint64_t origin_type_mask,
+ base::OnceCallback<void(/*failed_data_types=*/uint64_t)> callback) override;
+ std::vector<std::string> GetDomainsForDeferredCookieDeletion(
+ content::StoragePartition *storage_partition,
+ uint64_t remove_mask) override;
};
} // namespace QtWebEngineCore
diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h
index b61845e7b..cbcb60f8a 100644
--- a/src/core/certificate_error_controller.h
+++ b/src/core/certificate_error_controller.h
@@ -16,8 +16,10 @@
#define CERTIFICATE_ERROR_CONTROLLER_H
#include "qtwebenginecoreglobal_p.h"
-#include "base/callback.h"
+
+#include "base/functional/callback.h"
#include "content/public/browser/certificate_request_result_type.h"
+
#include "qwebenginecertificateerror.h"
#include <QtCore/QDateTime>
#include <QtCore/QScopedPointer>
@@ -31,7 +33,7 @@ class GURL;
namespace QtWebEngineCore {
-class Q_WEBENGINECORE_PRIVATE_EXPORT CertificateErrorController {
+class Q_WEBENGINECORE_EXPORT CertificateErrorController {
public:
CertificateErrorController(
int cert_error, const net::SSLInfo &ssl_info, const GURL &request_url,
diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp
index b75e5a5e6..28917e6c5 100644
--- a/src/core/chromium_overrides.cpp
+++ b/src/core/chromium_overrides.cpp
@@ -45,11 +45,12 @@ void *GetQtXDisplay()
namespace content {
class RenderViewHostDelegateView;
-std::unique_ptr<WebContentsView> CreateWebContentsView(WebContentsImpl *web_contents,
- std::unique_ptr<WebContentsViewDelegate> delegate,
- RenderViewHostDelegateView **render_view_host_delegate_view)
+std::unique_ptr<WebContentsView> CreateWebContentsView(
+ WebContentsImpl *web_contents,
+ std::unique_ptr<WebContentsViewDelegate> delegate,
+ raw_ptr<RenderViewHostDelegateView>* render_view_host_delegate_view)
{
- QtWebEngineCore::WebContentsViewQt* rv = new QtWebEngineCore::WebContentsViewQt(web_contents);
+ QtWebEngineCore::WebContentsViewQt *rv = new QtWebEngineCore::WebContentsViewQt(web_contents);
*render_view_host_delegate_view = rv;
return std::unique_ptr<WebContentsView>(rv);
}
@@ -132,12 +133,6 @@ std::unique_ptr<ui::OSExchangeDataProvider> ui::OSExchangeDataProviderFactory::C
return nullptr;
}
-#if !BUILDFLAG(ENABLE_EXTENSIONS)
-namespace extensions {
- const char kExtensionScheme[] = "chrome-extension";
-}
-#endif
-
#if !QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions)
namespace extensions {
ExtensionFunction::ResponseAction WebrtcLoggingPrivateSetMetaDataFunction::Run()
diff --git a/src/core/client_cert_select_controller.cpp b/src/core/client_cert_select_controller.cpp
index a4ce6f6da..d6af984c1 100644
--- a/src/core/client_cert_select_controller.cpp
+++ b/src/core/client_cert_select_controller.cpp
@@ -3,7 +3,7 @@
#include "client_cert_select_controller.h"
-#include <base/bind.h>
+#include <base/functional/bind.h>
#include <content/public/browser/client_certificate_delegate.h>
#include <net/cert/x509_certificate.h>
#include <net/ssl/client_cert_identity.h>
@@ -77,7 +77,8 @@ void ClientCertSelectController::select(const QSslCertificate &certificate)
}
QByteArray derCertificate = certificate.toDer();
scoped_refptr<net::X509Certificate> selectedCert =
- net::X509Certificate::CreateFromBytes(base::make_span((const unsigned char *)derCertificate.constData(), derCertificate.length()));
+ net::X509Certificate::CreateFromBytes(base::make_span((const unsigned char *)derCertificate.constData(),
+ (long unsigned)derCertificate.length()));
for (auto &certInfo : m_clientCerts) {
scoped_refptr<net::X509Certificate> cert = certInfo->certificate();
if (cert->EqualsExcludingChain(selectedCert.get())) {
diff --git a/src/core/client_cert_select_controller.h b/src/core/client_cert_select_controller.h
index 4807f11f1..8380a7845 100644
--- a/src/core/client_cert_select_controller.h
+++ b/src/core/client_cert_select_controller.h
@@ -34,7 +34,7 @@ class SSLCertRequestInfo;
namespace QtWebEngineCore {
-class Q_WEBENGINECORE_PRIVATE_EXPORT ClientCertSelectController {
+class Q_WEBENGINECORE_EXPORT ClientCertSelectController {
public:
ClientCertSelectController(net::SSLCertRequestInfo *certRequestInfo,
std::vector<std::unique_ptr<net::ClientCertIdentity>> clientCerts,
diff --git a/src/core/client_hints.cpp b/src/core/client_hints.cpp
index 2a30bb51b..9fa7531da 100644
--- a/src/core/client_hints.cpp
+++ b/src/core/client_hints.cpp
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "client_hints.h"
+#include "profile_qt.h"
#include "web_contents_delegate_qt.h"
#include "web_engine_settings.h"
@@ -59,6 +60,7 @@ content::BrowserContext *ClientHintsFactory::GetBrowserContextToUse(content::Bro
// found in the LICENSE file.
ClientHints::ClientHints(content::BrowserContext *context)
+ : context_(context)
{
}
@@ -81,8 +83,9 @@ void ClientHints::PersistClientHints(const url::Origin &primary_origin,
return;
blink::EnabledClientHints enabled_hints;
+ ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(context_)->profileAdapter();
for (auto hint : client_hints) {
- enabled_hints.SetIsEnabled(hint, true);
+ enabled_hints.SetIsEnabled(hint, profileAdapter->clientHintsEnabled());
}
accept_ch_cache_[primary_origin] = enabled_hints;
}
@@ -103,8 +106,9 @@ void ClientHints::GetAllowedClientHintsFromSource(const url::Origin &origin,
*client_hints = it->second;
}
+ ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(context_)->profileAdapter();
for (auto hint : additional_hints_)
- client_hints->SetIsEnabled(hint, true);
+ client_hints->SetIsEnabled(hint, profileAdapter->clientHintsEnabled());
}
void ClientHints::SetAdditionalClientHints(const std::vector<network::mojom::WebClientHintsType> &hints)
@@ -151,14 +155,14 @@ bool ClientHints::IsJavaScriptAllowed(const GURL &url, content::RenderFrameHost
return true;
}
-bool ClientHints::AreThirdPartyCookiesBlocked(const GURL &url)
+bool ClientHints::AreThirdPartyCookiesBlocked(const GURL &url, content::RenderFrameHost *rfh)
{
return false; // we probably can not report anything more specific
}
blink::UserAgentMetadata ClientHints::GetUserAgentMetadata()
{
- return embedder_support::GetUserAgentMetadata();
+ return static_cast<ProfileQt *>(context_)->userAgentMetadata();
}
void ClientHints::SetMostRecentMainFrameViewportSize(
diff --git a/src/core/client_hints.h b/src/core/client_hints.h
index a80629fc9..193982d16 100644
--- a/src/core/client_hints.h
+++ b/src/core/client_hints.h
@@ -58,7 +58,7 @@ public:
bool IsJavaScriptAllowed(const GURL &url, content::RenderFrameHost *parent_rfh) override;
- bool AreThirdPartyCookiesBlocked(const GURL &url) override;
+ bool AreThirdPartyCookiesBlocked(const GURL &url, content::RenderFrameHost *rfh) override;
blink::UserAgentMetadata GetUserAgentMetadata() override;
diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp
index 009235a72..3f49c6e3c 100644
--- a/src/core/clipboard_qt.cpp
+++ b/src/core/clipboard_qt.cpp
@@ -12,6 +12,7 @@
#include "base/logging.h"
#include "base/strings/utf_offset_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
+#include "base/types/variant_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/clipboard/clipboard.h"
@@ -27,6 +28,8 @@
#include <QImageWriter>
#include <QMimeData>
+#include <memory>
+
namespace QtWebEngineCore {
static void registerMetaTypes()
@@ -60,12 +63,12 @@ using namespace QtWebEngineCore;
namespace {
-QScopedPointer<QMimeData> uncommittedData;
+std::unique_ptr<QMimeData> uncommittedData;
QMimeData *getUncommittedData()
{
if (!uncommittedData)
uncommittedData.reset(new QMimeData);
- return uncommittedData.data();
+ return uncommittedData.get();
}
} // namespace
@@ -96,24 +99,23 @@ void ClipboardQt::WritePortableAndPlatformRepresentations(ui::ClipboardBuffer ty
DCHECK(CalledOnValidThread());
DCHECK(IsSupportedClipboardBuffer(type));
- for (const auto &object : objects)
- DispatchPortableRepresentation(object.first, object.second);
-
if (!platform_representations.empty())
DispatchPlatformRepresentations(std::move(platform_representations));
+ for (const auto &object : objects)
+ DispatchPortableRepresentation(object.second);
// Commit the accumulated data.
if (uncommittedData)
- QGuiApplication::clipboard()->setMimeData(uncommittedData.take(),
+ QGuiApplication::clipboard()->setMimeData(uncommittedData.release(),
type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard
: QClipboard::Selection);
if (type == ui::ClipboardBuffer::kCopyPaste && IsSupportedClipboardBuffer(ui::ClipboardBuffer::kSelection)) {
- ObjectMap::const_iterator text_iter = objects.find(PortableFormat::kText);
+ auto text_iter = objects.find(base::VariantIndexOfType<Data, TextData>());
if (text_iter != objects.end()) {
// Copy text and SourceTag to the selection clipboard.
WritePortableAndPlatformRepresentations(ui::ClipboardBuffer::kSelection,
- ObjectMap(text_iter, text_iter + 1),
+ ObjectMap(text_iter, ++text_iter),
{},
nullptr);
}
@@ -121,14 +123,14 @@ void ClipboardQt::WritePortableAndPlatformRepresentations(ui::ClipboardBuffer ty
m_dataSrc[type] = std::move(data_src);
}
-void ClipboardQt::WriteText(const char *text_data, size_t text_len)
+void ClipboardQt::WriteText(base::StringPiece text)
{
- getUncommittedData()->setText(QString::fromUtf8(text_data, text_len));
+ getUncommittedData()->setText(toQString(text));
}
-void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const char *url_data, size_t url_len)
+void ClipboardQt::WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url)
{
- QString markup_string = QString::fromUtf8(markup_data, markup_len);
+ QString markup_string = toQString(markup);
#if defined (Q_OS_MACOS)
// We need to prepend the charset on macOS to prevent garbled Unicode characters
// when pasting to certain applications (e.g. Notes, TextEdit)
@@ -139,11 +141,11 @@ void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const ch
#if !defined(Q_OS_WIN)
getUncommittedData()->setHtml(markup_string);
#else
- std::string url;
- if (url_len > 0)
- url.assign(url_data, url_len);
+ QString url;
+ if (source_url)
+ url = toQString(*source_url);
- std::string cf_html = HtmlToCFHtml(markup_string.toStdString(), url);
+ std::string cf_html = HtmlToCFHtml(markup_string.toStdString(), url.toStdString());
size_t html_start = std::string::npos;
size_t fragment_start = std::string::npos;
size_t fragment_end = std::string::npos;
@@ -157,9 +159,9 @@ void ClipboardQt::WriteHTML(const char *markup_data, size_t markup_len, const ch
#endif // !defined(Q_OS_WIN)
}
-void ClipboardQt::WriteRTF(const char *rtf_data, size_t data_len)
+void ClipboardQt::WriteRTF(base::StringPiece rtf)
{
- getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeRTF), QByteArray(rtf_data, data_len));
+ getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeRTF), toQByteArray(rtf));
}
void ClipboardQt::WriteWebSmartPaste()
@@ -172,12 +174,12 @@ void ClipboardQt::WriteBitmap(const SkBitmap &bitmap)
getUncommittedData()->setImageData(toQImage(bitmap).copy());
}
-void ClipboardQt::WriteBookmark(const char *title_data, size_t title_len, const char *url_data, size_t url_len)
+void ClipboardQt::WriteBookmark(base::StringPiece title_in, base::StringPiece url_in)
{
// FIXME: Untested, seems to be used only for drag-n-drop.
// Write as a mozilla url (UTF16: URL, newline, title).
- QString url = QString::fromUtf8(url_data, url_len);
- QString title = QString::fromUtf8(title_data, title_len);
+ QString url = toQString(url_in);
+ QString title = toQString(title_in);
QByteArray data;
data.append(reinterpret_cast<const char *>(url.utf16()), url.size() * 2);
@@ -186,9 +188,9 @@ void ClipboardQt::WriteBookmark(const char *title_data, size_t title_len, const
getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeMozillaURL), data);
}
-void ClipboardQt::WriteData(const ui::ClipboardFormatType &format, const char *data_data, size_t data_len)
+void ClipboardQt::WriteData(const ui::ClipboardFormatType &format, base::span<const uint8_t> data)
{
- getUncommittedData()->setData(QString::fromStdString(format.GetName()), QByteArray(data_data, data_len));
+ getUncommittedData()->setData(QString::fromStdString(format.GetName()), QByteArray((const char *)data.data(), data.size()));
}
bool ClipboardQt::IsFormatAvailable(const ui::ClipboardFormatType &format,
@@ -361,10 +363,10 @@ void ClipboardQt::ReadSvg(ui::ClipboardBuffer clipboard_type,
*result = toString16(QString::fromUtf8(svgData));
}
-void ClipboardQt::WriteSvg(const char *svg_data, size_t data_len)
+void ClipboardQt::WriteSvg(base::StringPiece markup)
{
getUncommittedData()->setData(QString::fromLatin1(ui::kMimeTypeSvg),
- QByteArray(svg_data, data_len));
+ toQByteArray(markup));
}
void ClipboardQt::ReadData(const ui::ClipboardFormatType &format,
@@ -418,6 +420,11 @@ void ClipboardQt::WriteFilenames(std::vector<ui::FileInfo> filenames)
getUncommittedData()->setUrls(urls);
}
+void ClipboardQt::WriteUnsanitizedHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url)
+{
+ WriteHTML(std::move(markup), std::move(source_url));
+}
+
#if defined(USE_OZONE)
bool ClipboardQt::IsSelectionBufferAvailable() const
{
diff --git a/src/core/clipboard_qt.h b/src/core/clipboard_qt.h
index 0351112e6..22f24cfe5 100644
--- a/src/core/clipboard_qt.h
+++ b/src/core/clipboard_qt.h
@@ -42,20 +42,21 @@ public:
std::vector<ui::FileInfo> *result) const override;
protected:
- void WritePortableAndPlatformRepresentations(
- ui::ClipboardBuffer buffer,
- const ObjectMap &objects,
- std::vector<Clipboard::PlatformRepresentation> platform_representations,
- std::unique_ptr<ui::DataTransferEndpoint> data_src) override;
- void WriteText(const char *text_data, size_t text_len) override;
- void WriteHTML(const char *markup_data, size_t markup_len, const char *url_data, size_t url_len) override;
- void WriteRTF(const char *rtf_data, size_t data_len) override;
- void WriteBookmark(const char *title_data, size_t title_len, const char *url_data, size_t url_len) override;
+ void WritePortableAndPlatformRepresentations(ui::ClipboardBuffer buffer,
+ const ObjectMap &objects,
+ std::vector<Clipboard::PlatformRepresentation> platform_representations,
+ std::unique_ptr<ui::DataTransferEndpoint> data_src) override;
+
+ void WriteText(base::StringPiece text) override;
+ void WriteHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) override;
+ void WriteRTF(base::StringPiece rtf) override;
+ void WriteBookmark(base::StringPiece title, base::StringPiece url) override;
void WriteWebSmartPaste() override;
void WriteBitmap(const SkBitmap &bitmap) override;
- void WriteData(const ui::ClipboardFormatType &format, const char *data_data, size_t data_len) override;
- void WriteSvg(const char *, size_t) override;
+ void WriteData(const ui::ClipboardFormatType &format, base::span<const uint8_t> data) override;
+ void WriteSvg(base::StringPiece markup) override;
void WriteFilenames(std::vector<ui::FileInfo> filenames) override;
+ void WriteUnsanitizedHTML(base::StringPiece markup, absl::optional<base::StringPiece> source_url) override;
base::flat_map<ui::ClipboardBuffer, std::unique_ptr<ui::DataTransferEndpoint>> m_dataSrc;
};
diff --git a/src/core/color_chooser_controller.h b/src/core/color_chooser_controller.h
index 7eafc143a..a97ebfbff 100644
--- a/src/core/color_chooser_controller.h
+++ b/src/core/color_chooser_controller.h
@@ -25,7 +25,7 @@ namespace QtWebEngineCore {
class ColorChooserControllerPrivate;
-class Q_WEBENGINECORE_PRIVATE_EXPORT ColorChooserController : public QObject {
+class Q_WEBENGINECORE_EXPORT ColorChooserController : public QObject {
Q_OBJECT
public:
~ColorChooserController();
diff --git a/src/core/compositor/compositor.cpp b/src/core/compositor/compositor.cpp
index fed395cb1..4c0bd4c0d 100644
--- a/src/core/compositor/compositor.cpp
+++ b/src/core/compositor/compositor.cpp
@@ -7,7 +7,6 @@
#include "components/viz/common/surfaces/frame_sink_id.h"
#include <QHash>
-#include <QImage>
#include <QMutex>
#include <QQuickWindow>
@@ -94,10 +93,8 @@ void Compositor::Observer::unbind()
Compositor::Handle<Compositor> Compositor::Observer::compositor()
{
- if (!m_binding)
- return nullptr;
g_bindings.lock();
- if (m_binding->compositor)
+ if (m_binding && m_binding->compositor)
return m_binding->compositor; // delay unlock
g_bindings.unlock();
return nullptr;
@@ -128,50 +125,34 @@ void Compositor::unbind()
Compositor::Handle<Compositor::Observer> Compositor::observer()
{
- if (!m_binding)
- return nullptr;
g_bindings.lock();
- if (m_binding->observer)
+ if (m_binding && m_binding->observer)
return m_binding->observer; // delay unlock
g_bindings.unlock();
return nullptr;
}
-QImage Compositor::image()
-{
- Q_UNREACHABLE();
- return {};
-}
-
void Compositor::waitForTexture()
{
- Q_UNREACHABLE();
}
-int Compositor::textureId()
+void Compositor::releaseTexture()
{
- Q_UNREACHABLE();
- return 0;
}
-#if QT_CONFIG(webengine_vulkan)
-VkImage Compositor::vkImage(QQuickWindow *)
+QSGTexture *Compositor::texture(QQuickWindow *, uint32_t textureOptions)
{
Q_UNREACHABLE();
- return {};
+ return nullptr;
}
-VkImageLayout Compositor::vkImageLayout()
+bool Compositor::textureIsFlipped()
{
Q_UNREACHABLE();
- return {};
+ return false;
}
-void Compositor::releaseVulkanResources(QQuickWindow *)
-{
- Q_UNREACHABLE();
-}
-#endif
+void Compositor::releaseResources() { }
// static
void Compositor::unlockBindings()
diff --git a/src/core/compositor/compositor.h b/src/core/compositor/compositor.h
index 7c6590134..501559060 100644
--- a/src/core/compositor/compositor.h
+++ b/src/core/compositor/compositor.h
@@ -4,17 +4,12 @@
#ifndef COMPOSITOR_H
#define COMPOSITOR_H
-#include <QtGui/qtguiglobal.h>
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
-#if QT_CONFIG(webengine_vulkan)
-#include <QVulkanInstance>
-#endif
-
QT_BEGIN_NAMESPACE
-class QImage;
class QQuickWindow;
class QSize;
+class QSGTexture;
QT_END_NAMESPACE
namespace viz {
@@ -25,10 +20,9 @@ namespace QtWebEngineCore {
// Produces composited frames for display.
//
-// Used by quick/widgets libraries for accessing the frame and
-// controlling frame swapping. Must be cast to a subclass to access
-// the frame as QImage or OpenGL texture, etc.
-class Q_WEBENGINECORE_PRIVATE_EXPORT Compositor
+// Used by quick/widgets libraries for accessing the frames and
+// controlling frame swapping.
+class Q_WEBENGINECORE_EXPORT Compositor
{
struct Binding;
@@ -36,8 +30,8 @@ public:
// Identifies the implementation type.
enum class Type {
Software,
- OpenGL,
- Vulkan,
+ OpenGL, // TODO: Legacy, remove it with DisplaySkiaOutputDevice!
+ Native
};
// Identifies a compositor.
@@ -81,7 +75,7 @@ public:
// Observes the compositor corresponding to the given id.
//
// Only one observer can exist per compositor.
- class Q_WEBENGINECORE_PRIVATE_EXPORT Observer
+ class Q_WEBENGINECORE_EXPORT Observer
{
public:
// Binding to compositor
@@ -124,38 +118,22 @@ public:
virtual QSize size() = 0;
// Whether frame needs an alpha channel.
- //
- // In software mode, the image format can be either
- // QImage::Format_ARGB32_Premultiplied or
- // QImage::Format_RGBA8888_Premultiplied
- //
- // In OpenGL mode, the texture format is either GL_RGBA or GL_RGB.
- virtual bool hasAlphaChannel() = 0;
-
- // (Software) QImage of the frame.
- //
- // This is a big image so we should try not to make copies of it.
- // In particular, the client should drop its QImage reference
- // before calling swapFrame(), otherwise each swap will cause a
- // detach.
- virtual QImage image();
+ virtual bool requiresAlphaChannel() = 0;
- // (OpenGL) Wait on texture fence in Qt's current OpenGL context.
+ // Wait on texture to be ready aka. sync.
virtual void waitForTexture();
- // (OpenGL) Texture of the frame.
- virtual int textureId();
+ // Release any held texture resources
+ virtual void releaseTexture();
-#if QT_CONFIG(webengine_vulkan)
- // (Vulkan) VkImage of the frame.
- virtual VkImage vkImage(QQuickWindow *win);
+ // QSGTexture of the frame.
+ virtual QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions);
- // (Vulkan) Layout for vkImage().
- virtual VkImageLayout vkImageLayout();
+ // Is the texture produced upside down?
+ virtual bool textureIsFlipped();
- // (Vulkan) Release Vulkan resources created by Qt's Vulkan instance.
- virtual void releaseVulkanResources(QQuickWindow *win);
-#endif
+ // Release resources created in texture()
+ virtual void releaseResources();
protected:
Compositor(Type type) : m_type(type) { }
diff --git a/src/core/compositor/content_gpu_client_qt.cpp b/src/core/compositor/content_gpu_client_qt.cpp
index 4c022dc7f..6ef8048f2 100644
--- a/src/core/compositor/content_gpu_client_qt.cpp
+++ b/src/core/compositor/content_gpu_client_qt.cpp
@@ -2,8 +2,7 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "content_gpu_client_qt.h"
-
-#include "web_engine_context.h"
+#include "ozone/gl_share_context_qt.h"
namespace QtWebEngineCore {
@@ -15,9 +14,11 @@ ContentGpuClientQt::~ContentGpuClientQt()
{
}
-gpu::SyncPointManager *ContentGpuClientQt::GetSyncPointManager()
+gl::GLShareGroup *ContentGpuClientQt::GetInProcessGpuShareGroup()
{
- return WebEngineContext::syncPointManager();
+ if (!m_shareGroupQt.get())
+ m_shareGroupQt = new ShareGroupQt;
+ return m_shareGroupQt.get();
}
} // namespace
diff --git a/src/core/compositor/content_gpu_client_qt.h b/src/core/compositor/content_gpu_client_qt.h
index 75d9d68be..33314e0bb 100644
--- a/src/core/compositor/content_gpu_client_qt.h
+++ b/src/core/compositor/content_gpu_client_qt.h
@@ -5,7 +5,12 @@
#include "content/public/gpu/content_gpu_client.h"
+namespace gl {
+class GLShareGroup;
+}
+
namespace QtWebEngineCore {
+class ShareGroupQt;
class ContentGpuClientQt : public content::ContentGpuClient {
public:
@@ -13,7 +18,10 @@ public:
~ContentGpuClientQt() override;
// content::ContentGpuClient implementation.
- gpu::SyncPointManager *GetSyncPointManager() override;
+ gl::GLShareGroup *GetInProcessGpuShareGroup() override;
+
+private:
+ scoped_refptr<ShareGroupQt> m_shareGroupQt;
};
}
diff --git a/src/core/compositor/display_overrides.cpp b/src/core/compositor/display_overrides.cpp
index aa86861d2..ebaa96dbb 100644
--- a/src/core/compositor/display_overrides.cpp
+++ b/src/core/compositor/display_overrides.cpp
@@ -3,50 +3,98 @@
#include "display_skia_output_device.h"
#include "display_software_output_surface.h"
+#include "native_skia_output_device.h"
#include "components/viz/service/display_embedder/output_surface_provider_impl.h"
#include "components/viz/service/display_embedder/skia_output_surface_impl_on_gpu.h"
#include "gpu/ipc/in_process_command_buffer.h"
+
#include <qtgui-config.h>
+#include <QtQuick/qquickwindow.h>
+
+#if QT_CONFIG(opengl)
+#include "native_skia_output_device_opengl.h"
+#endif
+
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "native_skia_output_device_vulkan.h"
+#endif
+
+#if defined(Q_OS_WIN)
+#include "native_skia_output_device_direct3d11.h"
+#endif
+
+#if defined(Q_OS_MACOS)
+#include "native_skia_output_device_metal.h"
+#endif
std::unique_ptr<viz::OutputSurface>
-viz::OutputSurfaceProviderImpl::CreateSoftwareOutputSurface()
+viz::OutputSurfaceProviderImpl::CreateSoftwareOutputSurface(const RendererSettings &renderer_settings)
{
- return std::make_unique<QtWebEngineCore::DisplaySoftwareOutputSurface>();
+ return std::make_unique<QtWebEngineCore::DisplaySoftwareOutputSurface>(renderer_settings.requires_alpha_channel);
}
std::unique_ptr<viz::SkiaOutputDevice>
viz::SkiaOutputSurfaceImplOnGpu::CreateOutputDevice()
{
+ static const auto graphicsApi = QQuickWindow::graphicsApi();
+
#if QT_CONFIG(opengl)
- return std::make_unique<QtWebEngineCore::DisplaySkiaOutputDevice>(
- context_state_,
- shared_gpu_deps_->memory_tracker(),
- GetDidSwapBuffersCompleteCallback());
+ if (graphicsApi == QSGRendererInterface::OpenGL) {
+ if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE) {
+#if !defined(Q_OS_MACOS)
+ return std::make_unique<QtWebEngineCore::DisplaySkiaOutputDevice>(
+ context_state_, renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(), GetDidSwapBuffersCompleteCallback());
#else
- return nullptr;
+ qFatal("macOS only supports ANGLE.");
+#endif // !defined(Q_OS_MACOS)
+ }
+
+ return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceOpenGL>(
+ context_state_, renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(),
+ shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback());
+ }
#endif // QT_CONFIG(opengl)
-}
-void gpu::InProcessCommandBuffer::GetTextureQt(
- unsigned int client_id,
- GetTextureCallback callback,
- const std::vector<SyncToken>& sync_token_fences)
-{
- ScheduleGpuTask(base::BindOnce(&InProcessCommandBuffer::GetTextureQtOnGpuThread,
- gpu_thread_weak_ptr_factory_.GetWeakPtr(),
- client_id,
- std::move(callback)),
- sync_token_fences);
-}
+#if BUILDFLAG(ENABLE_VULKAN)
+ if (graphicsApi == QSGRendererInterface::Vulkan) {
+#if !defined(Q_OS_MACOS)
+ return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceVulkan>(
+ context_state_, renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(),
+ shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback());
+#else
+ qFatal("Vulkan is not supported on macOS.");
+#endif // !defined(Q_OS_MACOS)
+ }
+#endif // BUILDFLAG(ENABLE_VULKAN)
-void gpu::InProcessCommandBuffer::GetTextureQtOnGpuThread(
- unsigned int client_id, GetTextureCallback callback)
-{
- if (!MakeCurrent()) {
- LOG(ERROR) << "MakeCurrent failed for GetTextureQt";
- return;
+#if defined(Q_OS_WIN)
+ if (graphicsApi == QSGRendererInterface::Direct3D11) {
+ if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE)
+ qFatal("Direct3D11 is only supported over ANGLE.");
+
+ return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceDirect3D11>(
+ context_state_, renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(),
+ shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback());
}
- gpu::TextureBase *texture = decoder_->GetTextureBase(client_id);
- std::move(callback).Run(texture ? texture->service_id() : 0, gl::GLFence::Create());
+#endif
+
+#if defined(Q_OS_MACOS)
+ if (graphicsApi == QSGRendererInterface::Metal) {
+ if (gl::GetGLImplementation() != gl::kGLImplementationEGLANGLE)
+ qFatal("Metal is only supported over ANGLE.");
+
+ return std::make_unique<QtWebEngineCore::NativeSkiaOutputDeviceMetal>(
+ context_state_, renderer_settings_.requires_alpha_channel,
+ shared_gpu_deps_->memory_tracker(), dependency_.get(), shared_image_factory_.get(),
+ shared_image_representation_factory_.get(), GetDidSwapBuffersCompleteCallback());
+ }
+#endif
+
+ qFatal() << "Unsupported Graphics API:" << graphicsApi;
+ return nullptr;
}
diff --git a/src/core/compositor/display_skia_output_device.cpp b/src/core/compositor/display_skia_output_device.cpp
index 7f42d61de..0ca466fe8 100644
--- a/src/core/compositor/display_skia_output_device.cpp
+++ b/src/core/compositor/display_skia_output_device.cpp
@@ -3,34 +3,16 @@
#include "display_skia_output_device.h"
+#include "compositor_resource_fence.h"
#include "type_conversion.h"
#include "gpu/command_buffer/service/skia_utils.h"
+#include "third_party/skia/include/core/SkSurface.h"
#include "third_party/skia/include/core/SkSurfaceProps.h"
+#include "third_party/skia/include/gpu/ganesh/SkSurfaceGanesh.h"
+#include "third_party/skia/include/gpu/ganesh/gl/GrGLBackendSurface.h"
-#if QT_CONFIG(webengine_vulkan)
-#if defined(USE_OZONE)
-#include "ui/ozone/buildflags.h"
-#if BUILDFLAG(OZONE_PLATFORM_X11)
-// We need to define USE_VULKAN_XCB for proper vulkan function pointers.
-// Avoiding it may lead to call wrong vulkan functions.
-// This is originally defined in chromium/gpu/vulkan/BUILD.gn.
-#define USE_VULKAN_XCB
-#endif // BUILDFLAG(OZONE_PLATFORM_X11)
-#endif // defined(USE_OZONE)
-#include "gpu/vulkan/vulkan_function_pointers.h"
-
-#include "components/viz/common/gpu/vulkan_context_provider.h"
-#include "compositor/display_skia_output_device.h"
-#include "gpu/vulkan/vma_wrapper.h"
-#include "gpu/vulkan/vulkan_device_queue.h"
-#include "third_party/vulkan_memory_allocator/include/vk_mem_alloc.h"
-
-#include <QQuickWindow>
-#include <QVulkanInstance>
-#include <QVulkanFunctions>
-#include <QVulkanDeviceFunctions>
-#endif // QT_CONFIG(webengine_vulkan)
+#include <QSGTexture>
namespace QtWebEngineCore {
@@ -41,29 +23,25 @@ public:
: m_parent(parent)
, m_shape(m_parent->m_shape)
{
- const auto &colorType = m_shape.characterization.colorType();
+ }
+ void initialize()
+ {
+ const auto &colorType = m_shape.imageInfo.colorType();
DCHECK(colorType != kUnknown_SkColorType);
m_texture = m_parent->m_contextState->gr_context()->createBackendTexture(
- m_shape.characterization.width(), m_shape.characterization.height(), colorType,
+ m_shape.imageInfo.width(), m_shape.imageInfo.height(), colorType,
GrMipMapped::kNo, GrRenderable::kYes);
DCHECK(m_texture.isValid());
- if (m_texture.backend() == GrBackendApi::kVulkan) {
-#if QT_CONFIG(webengine_vulkan)
- initVulkan();
-#else
- NOTREACHED();
-#endif
- } else {
- auto info = SkImageInfo::Make(m_shape.characterization.width(), m_shape.characterization.height(),
- colorType, kUnpremul_SkAlphaType);
- m_estimatedSize = info.computeMinByteSize();
- }
+ DCHECK(m_texture.backend() == GrBackendApi::kOpenGL);
+ auto info = SkImageInfo::Make(m_shape.imageInfo.width(), m_shape.imageInfo.height(),
+ colorType, kUnpremul_SkAlphaType);
+ m_estimatedSize = info.computeMinByteSize();
m_parent->memory_type_tracker_->TrackMemAlloc(m_estimatedSize);
SkSurfaceProps surfaceProps = SkSurfaceProps{0, kUnknown_SkPixelGeometry};
- m_surface = SkSurface::MakeFromBackendTexture(
+ m_surface = SkSurfaces::WrapBackendTexture(
m_parent->m_contextState->gr_context(), m_texture,
m_parent->capabilities_.output_surface_origin == gfx::SurfaceOrigin::kTopLeft
? kTopLeft_GrSurfaceOrigin
@@ -74,11 +52,10 @@ public:
~Buffer()
{
-#if QT_CONFIG(webengine_vulkan) && defined(Q_OS_WIN)
- CloseHandle(m_win32Handle);
-#endif
- DeleteGrBackendTexture(m_parent->m_contextState.get(), &m_texture);
- m_parent->memory_type_tracker_->TrackMemFree(m_estimatedSize);
+ if (m_texture.isValid()) {
+ DeleteGrBackendTexture(m_parent->m_contextState.get(), &m_texture);
+ m_parent->memory_type_tracker_->TrackMemFree(m_estimatedSize);
+ }
}
void createFence()
@@ -98,42 +75,6 @@ public:
const GrBackendTexture &texture() const { return m_texture; }
SkSurface *surface() const { return m_surface.get(); }
-#if QT_CONFIG(webengine_vulkan)
- const VkImageCreateInfo *imageCreateInfo() const { return &m_imageCreateInfo; }
- uint64_t allocationSize() const { return m_estimatedSize; }
- VkImageLayout imageLayout() const { return m_imageLayout; }
- uint32_t memoryTypeIndex() const { return m_memoryTypeIndex.value(); }
-
-#if defined(Q_OS_WIN)
- const VkExternalMemoryHandleTypeFlagBits externalMemoryHandleType() const
- {
- return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_BIT_KHR;
- }
-
- HANDLE externalMemoryHandle() const { return m_win32Handle; }
-#else
- const VkExternalMemoryHandleTypeFlagBits externalMemoryHandleType() const
- {
- return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
- }
-
- int externalMemoryHandle() const
- {
- VkMemoryGetFdInfoKHR exportInfo = { VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR };
- exportInfo.pNext = nullptr;
- exportInfo.memory = m_imageInfo.fAlloc.fMemory;
- exportInfo.handleType = externalMemoryHandleType();
-
- // Importing Vulkan memory object closes the file descriptor.
- int fd = -1;
- if (m_vfp->vkGetMemoryFdKHR(m_vulkanDevice, &exportInfo, &fd) != VK_SUCCESS)
- qFatal("VULKAN: Unable to extract file descriptor out of external VkImage!");
-
- return fd;
- }
-#endif // defined(Q_OS_WIN)
-#endif // QT_CONFIG(webengine_vulkan)
-
private:
DisplaySkiaOutputDevice *m_parent;
Shape m_shape;
@@ -141,129 +82,24 @@ private:
sk_sp<SkSurface> m_surface;
uint64_t m_estimatedSize = 0;
scoped_refptr<CompositorResourceFence> m_fence;
-
-#if QT_CONFIG(webengine_vulkan)
- static VkSampleCountFlagBits vkSampleCount(uint32_t sampleCount)
- {
- Q_ASSERT(sampleCount >= 1);
- switch (sampleCount) {
- case 1:
- return VK_SAMPLE_COUNT_1_BIT;
- case 2:
- return VK_SAMPLE_COUNT_2_BIT;
- case 4:
- return VK_SAMPLE_COUNT_4_BIT;
- case 8:
- return VK_SAMPLE_COUNT_8_BIT;
- case 16:
- return VK_SAMPLE_COUNT_16_BIT;
- default:
- Q_UNREACHABLE();
- }
-
- return VK_SAMPLE_COUNT_1_BIT;
- }
-
- void initVulkan()
- {
- bool success = m_texture.getVkImageInfo(&m_imageInfo);
- if (!success)
- qFatal("VULKAN: Failed to get external Vulkan resources from Skia!");
-
- m_vfp = gpu::GetVulkanFunctionPointers();
- gpu::VulkanDeviceQueue *vulkanDeviceQueue =
- m_parent->m_contextState->vk_context_provider()->GetDeviceQueue();
- m_vulkanDevice = vulkanDeviceQueue->GetVulkanDevice();
-
- // Store allocation size for the external VkImage.
- m_estimatedSize = m_imageInfo.fAlloc.fSize;
-
- // Store initial layout for the imported image.
- if (vulkanDeviceQueue->vk_physical_device_properties().vendorID == 0x10DE) {
- // FIXME: This is a workaround for Nvidia driver.
- // The imported image is empty if the initialLayout is not PREINITIALIZED.
- m_imageLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
- } else {
- // The initialLayout should be undefined for the external image.
- // https://registry.khronos.org/vulkan/specs/1.3-extensions/man/html/VkImageCreateInfo.html#VUID-VkImageCreateInfo-pNext-01443
- m_imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- }
-
- // Specify VkCreateImageInfo for the imported VkImage.
- // The specification should match with the texture's VkImage.
- m_externalMemoryImageCreateInfo.sType =
- VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR;
- m_externalMemoryImageCreateInfo.pNext = nullptr;
- m_externalMemoryImageCreateInfo.handleTypes = externalMemoryHandleType();
-
- m_imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
- m_imageCreateInfo.pNext = &m_externalMemoryImageCreateInfo;
- m_imageCreateInfo.flags =
- m_imageInfo.fProtected == GrProtected::kYes ? VK_IMAGE_CREATE_PROTECTED_BIT : 0;
- m_imageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
- m_imageCreateInfo.format = m_imageInfo.fFormat;
- m_imageCreateInfo.extent.width = static_cast<uint32_t>(m_shape.characterization.width());
- m_imageCreateInfo.extent.height = static_cast<uint32_t>(m_shape.characterization.height());
- m_imageCreateInfo.extent.depth = 1;
- m_imageCreateInfo.mipLevels = m_imageInfo.fLevelCount;
- m_imageCreateInfo.arrayLayers = 1;
- m_imageCreateInfo.samples = vkSampleCount(m_imageInfo.fSampleCount);
- m_imageCreateInfo.tiling = m_imageInfo.fImageTiling;
- m_imageCreateInfo.usage = m_imageInfo.fImageUsageFlags;
- m_imageCreateInfo.sharingMode = m_imageInfo.fSharingMode;
- m_imageCreateInfo.queueFamilyIndexCount = 0;
- m_imageCreateInfo.pQueueFamilyIndices = nullptr;
- m_imageCreateInfo.initialLayout = m_imageLayout;
-
-#if defined(Q_OS_WIN)
- // Extract Windows handle for the memory of the external VkImage.
- // Ownership should be released at the destruction of the Buffer object.
- // Multiple handles for the same memory cause issues on Windows even if one is
- // released before extracting the other.
- VkMemoryGetWin32HandleInfoKHR exportInfo = {
- VK_STRUCTURE_TYPE_MEMORY_GET_WIN32_HANDLE_INFO_KHR
- };
- exportInfo.pNext = nullptr;
- exportInfo.memory = m_imageInfo.fAlloc.fMemory;
- exportInfo.handleType = externalMemoryHandleType();
-
- if (m_vfp->vkGetMemoryWin32HandleKHR(m_vulkanDevice, &exportInfo, &m_win32Handle)
- != VK_SUCCESS) {
- qFatal("VULKAN: Unable to extract handle out of external VkImage!");
- }
-#endif // defined(Q_OS_WIN)
-
- VmaAllocator vmaAllocator = vulkanDeviceQueue->vma_allocator();
- const VmaAllocation vmaAllocation =
- reinterpret_cast<const VmaAllocation>(m_imageInfo.fAlloc.fBackendMemory);
- VmaAllocationInfo vmaInfo;
- gpu::vma::GetAllocationInfo(vmaAllocator, vmaAllocation, &vmaInfo);
- m_memoryTypeIndex = vmaInfo.memoryType;
- }
-
- gpu::VulkanFunctionPointers *m_vfp = nullptr;
- VkDevice m_vulkanDevice = VK_NULL_HANDLE;
- VkImageLayout m_imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
- GrVkImageInfo m_imageInfo;
- VkExternalMemoryImageCreateInfoKHR m_externalMemoryImageCreateInfo = {};
- VkImageCreateInfo m_imageCreateInfo = {};
-#if defined(Q_OS_WIN)
- HANDLE m_win32Handle = nullptr;
-#endif
- absl::optional<uint32_t> m_memoryTypeIndex;
-#endif // QT_CONFIG(webengine_vulkan)
};
DisplaySkiaOutputDevice::DisplaySkiaOutputDevice(
- scoped_refptr<gpu::SharedContextState> contextState, gpu::MemoryTracker *memoryTracker,
+ scoped_refptr<gpu::SharedContextState> contextState,
+ bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker,
DidSwapBufferCompleteCallback didSwapBufferCompleteCallback)
- : SkiaOutputDevice(contextState->gr_context(), memoryTracker, didSwapBufferCompleteCallback)
- , Compositor(contextState->GrContextIsVulkan() ? Compositor::Type::Vulkan
- : Compositor::Type::OpenGL)
+ : SkiaOutputDevice(contextState->gr_context(), contextState->graphite_context(),
+ memoryTracker, didSwapBufferCompleteCallback)
+ , Compositor(Compositor::Type::OpenGL)
, m_contextState(contextState)
+ , m_requiresAlpha(requiresAlpha)
{
capabilities_.uses_default_gl_framebuffer = false;
capabilities_.supports_surfaceless = true;
+ capabilities_.preserve_buffer_content = true;
+ capabilities_.only_invalidates_damage_rect = false;
+ capabilities_.number_of_buffers = 3;
capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] =
kRGBA_8888_SkColorType;
@@ -283,19 +119,20 @@ void DisplaySkiaOutputDevice::SetFrameSinkId(const viz::FrameSinkId &id)
{
bind(id);
}
-
-bool DisplaySkiaOutputDevice::Reshape(const SkSurfaceCharacterization &characterization,
+bool DisplaySkiaOutputDevice::Reshape(const SkImageInfo &image_info,
const gfx::ColorSpace &colorSpace,
+ int sample_count,
float device_scale_factor,
gfx::OverlayTransform transform)
{
- m_shape = Shape{characterization, device_scale_factor, colorSpace};
+ m_shape = Shape{image_info, device_scale_factor, colorSpace};
DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE);
return true;
}
-void DisplaySkiaOutputDevice::SwapBuffers(BufferPresentedCallback feedback,
- viz::OutputSurfaceFrame frame)
+void DisplaySkiaOutputDevice::Present(const absl::optional<gfx::Rect> &update_rect,
+ BufferPresentedCallback feedback,
+ viz::OutputSurfaceFrame frame)
{
DCHECK(m_backBuffer);
@@ -305,8 +142,8 @@ void DisplaySkiaOutputDevice::SwapBuffers(BufferPresentedCallback feedback,
{
QMutexLocker locker(&m_mutex);
- m_taskRunner = base::ThreadTaskRunnerHandle::Get();
- m_middleBuffer = std::move(m_backBuffer);
+ m_taskRunner = base::SingleThreadTaskRunner::GetCurrentDefault();
+ std::swap(m_middleBuffer, m_backBuffer);
m_readyToUpdate = true;
}
@@ -322,10 +159,12 @@ void DisplaySkiaOutputDevice::DiscardBackbuffer()
{
}
-SkSurface *DisplaySkiaOutputDevice::BeginPaint(std::vector<GrBackendSemaphore> *)
+SkSurface *DisplaySkiaOutputDevice::BeginPaint(std::vector<GrBackendSemaphore> *end_semaphores)
{
- if (!m_backBuffer || m_backBuffer->shape() != m_shape)
+ if (!m_backBuffer || m_backBuffer->shape() != m_shape) {
m_backBuffer = std::make_unique<Buffer>(this);
+ m_backBuffer->initialize();
+ }
return m_backBuffer->surface();
}
@@ -352,128 +191,49 @@ void DisplaySkiaOutputDevice::waitForTexture()
m_frontBuffer->consumeFence();
}
-int DisplaySkiaOutputDevice::textureId()
+QSGTexture *DisplaySkiaOutputDevice::texture(QQuickWindow *win, uint32_t textureOptions)
{
if (!m_frontBuffer)
- return 0;
-
- GrGLTextureInfo info;
- if (!m_frontBuffer->texture().getGLTextureInfo(&info))
- return 0;
+ return nullptr;
- return info.fID;
-}
+ QQuickWindow::CreateTextureOptions texOpts(textureOptions);
-QSize DisplaySkiaOutputDevice::size()
-{
- return m_frontBuffer ? toQt(m_frontBuffer->shape().characterization.dimensions()) : QSize();
+ QSGTexture *texture = nullptr;
+ GrGLTextureInfo info;
+ if (GrBackendTextures::GetGLTextureInfo(m_frontBuffer->texture(), &info))
+ texture = QNativeInterface::QSGOpenGLTexture::fromNative(info.fID, win, size(), texOpts);
+ return texture;
}
-bool DisplaySkiaOutputDevice::hasAlphaChannel()
+bool DisplaySkiaOutputDevice::textureIsFlipped()
{
return true;
}
-float DisplaySkiaOutputDevice::devicePixelRatio()
+QSize DisplaySkiaOutputDevice::size()
{
- return m_frontBuffer ? m_frontBuffer->shape().devicePixelRatio : 1;
+ return m_frontBuffer ? toQt(m_frontBuffer->shape().imageInfo.dimensions()) : QSize();
}
-#if QT_CONFIG(webengine_vulkan)
-VkImage DisplaySkiaOutputDevice::vkImage(QQuickWindow *win)
+bool DisplaySkiaOutputDevice::requiresAlphaChannel()
{
- if (!m_frontBuffer)
- return VK_NULL_HANDLE;
-
- QSGRendererInterface *ri = win->rendererInterface();
- VkDevice qtVulkanDevice =
- *static_cast<VkDevice *>(ri->getResource(win, QSGRendererInterface::DeviceResource));
- QVulkanDeviceFunctions *df = win->vulkanInstance()->deviceFunctions(qtVulkanDevice);
-
- df->vkDestroyImage(qtVulkanDevice, m_importedImage, nullptr);
- df->vkFreeMemory(qtVulkanDevice, m_importedImageMemory, nullptr);
-
- if (df->vkCreateImage(qtVulkanDevice, m_frontBuffer->imageCreateInfo(), nullptr,
- &m_importedImage)
- != VK_SUCCESS) {
- qFatal("VULKAN: Failed to create imported image!");
- }
-
- VkMemoryDedicatedAllocateInfoKHR dedicatedAllocateInfo = {
- VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR
- };
- dedicatedAllocateInfo.pNext = nullptr;
- dedicatedAllocateInfo.image = m_importedImage;
- dedicatedAllocateInfo.buffer = VK_NULL_HANDLE;
-
-#if defined(Q_OS_WIN)
- VkImportMemoryWin32HandleInfoKHR importInfo = {
- VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR
- };
- importInfo.handle = m_frontBuffer->externalMemoryHandle();
-#else
- VkImportMemoryFdInfoKHR importInfo = { VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR };
- importInfo.fd = m_frontBuffer->externalMemoryHandle();
-#endif // defined(Q_OS_WIN)
- importInfo.pNext = &dedicatedAllocateInfo;
- importInfo.handleType = m_frontBuffer->externalMemoryHandleType();
-
- VkMemoryAllocateInfo allocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
- allocateInfo.pNext = &importInfo;
- allocateInfo.allocationSize = m_frontBuffer->allocationSize();
- allocateInfo.memoryTypeIndex = m_frontBuffer->memoryTypeIndex();
-
- if (df->vkAllocateMemory(qtVulkanDevice, &allocateInfo, nullptr, &m_importedImageMemory)
- != VK_SUCCESS) {
- qFatal("VULKAN: Failed to allocate memory for imported VkImage!");
- }
-
- df->vkBindImageMemory(qtVulkanDevice, m_importedImage, m_importedImageMemory, 0);
-
- return m_importedImage;
-}
-
-VkImageLayout DisplaySkiaOutputDevice::vkImageLayout()
-{
- if (!m_frontBuffer)
- return VK_IMAGE_LAYOUT_UNDEFINED;
-
- return m_frontBuffer->imageLayout();
+ return m_requiresAlpha;
}
-void DisplaySkiaOutputDevice::releaseVulkanResources(QQuickWindow *win)
+float DisplaySkiaOutputDevice::devicePixelRatio()
{
- VkDevice *vkDevicePtr = static_cast<VkDevice *>(
- win->rendererInterface()->getResource(win, QSGRendererInterface::DeviceResource));
-
- if (!vkDevicePtr) {
- Q_ASSERT(m_importedImage == VK_NULL_HANDLE && m_importedImageMemory == VK_NULL_HANDLE);
- return;
- }
-
- QVulkanDeviceFunctions *df = win->vulkanInstance()->deviceFunctions(*vkDevicePtr);
-
- if (m_importedImage != VK_NULL_HANDLE) {
- df->vkDestroyImage(*vkDevicePtr, m_importedImage, nullptr);
- m_importedImage = VK_NULL_HANDLE;
- }
-
- if (m_importedImageMemory != VK_NULL_HANDLE) {
- df->vkFreeMemory(*vkDevicePtr, m_importedImageMemory, nullptr);
- m_importedImageMemory = VK_NULL_HANDLE;
- }
+ return m_frontBuffer ? m_frontBuffer->shape().devicePixelRatio : 1;
}
-#endif // QT_CONFIG(webengine_vulkan)
void DisplaySkiaOutputDevice::SwapBuffersFinished()
{
{
QMutexLocker locker(&m_mutex);
- m_backBuffer = std::move(m_middleBuffer);
+ std::swap(m_backBuffer, m_middleBuffer);
}
FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
- gfx::Size(m_shape.characterization.width(), m_shape.characterization.height()),
+ gfx::Size(m_shape.imageInfo.width(), m_shape.imageInfo.height()),
std::move(m_frame));
}
diff --git a/src/core/compositor/display_skia_output_device.h b/src/core/compositor/display_skia_output_device.h
index e2818d604..e6a97b810 100644
--- a/src/core/compositor/display_skia_output_device.h
+++ b/src/core/compositor/display_skia_output_device.h
@@ -4,15 +4,15 @@
#ifndef DISPLAY_SKIA_OUTPUT_DEVICE_H
#define DISPLAY_SKIA_OUTPUT_DEVICE_H
-#include "compositor_resource_fence.h"
+#include <QtCore/QMutex>
+#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+
#include "compositor.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "components/viz/service/display_embedder/skia_output_device.h"
#include "gpu/command_buffer/service/shared_context_state.h"
-#include <QMutex>
-
QT_BEGIN_NAMESPACE
class QQuickWindow;
QT_END_NAMESPACE
@@ -23,18 +23,21 @@ class DisplaySkiaOutputDevice final : public viz::SkiaOutputDevice, public Compo
{
public:
DisplaySkiaOutputDevice(scoped_refptr<gpu::SharedContextState> contextState,
+ bool requiresAlpha,
gpu::MemoryTracker *memoryTracker,
DidSwapBufferCompleteCallback didSwapBufferCompleteCallback);
~DisplaySkiaOutputDevice() override;
// Overridden from SkiaOutputDevice.
void SetFrameSinkId(const viz::FrameSinkId &frame_sink_id) override;
- bool Reshape(const SkSurfaceCharacterization &characterization,
- const gfx::ColorSpace& colorSpace,
+ bool Reshape(const SkImageInfo &image_info,
+ const gfx::ColorSpace &color_space,
+ int sample_count,
float device_scale_factor,
gfx::OverlayTransform transform) override;
- void SwapBuffers(BufferPresentedCallback feedback,
- viz::OutputSurfaceFrame frame) override;
+ void Present(const absl::optional<gfx::Rect>& update_rect,
+ BufferPresentedCallback feedback,
+ viz::OutputSurfaceFrame frame) override;
void EnsureBackbuffer() override;
void DiscardBackbuffer() override;
SkSurface *BeginPaint(std::vector<GrBackendSemaphore> *semaphores) override;
@@ -43,26 +46,22 @@ public:
// Overridden from Compositor.
void swapFrame() override;
void waitForTexture() override;
- int textureId() override;
+ QSGTexture *texture(QQuickWindow *win, uint32_t texOpts) override;
+ bool textureIsFlipped() override;
QSize size() override;
- bool hasAlphaChannel() override;
+ bool requiresAlphaChannel() override;
float devicePixelRatio() override;
-#if QT_CONFIG(webengine_vulkan)
- VkImage vkImage(QQuickWindow *win) override;
- VkImageLayout vkImageLayout() override;
- void releaseVulkanResources(QQuickWindow *win) override;
-#endif
private:
struct Shape
{
- SkSurfaceCharacterization characterization;
+ SkImageInfo imageInfo;
float devicePixelRatio;
gfx::ColorSpace colorSpace;
bool operator==(const Shape &that) const
{
- return (characterization == that.characterization &&
+ return (imageInfo == that.imageInfo &&
devicePixelRatio == that.devicePixelRatio &&
colorSpace == that.colorSpace);
}
@@ -81,12 +80,8 @@ private:
std::unique_ptr<Buffer> m_backBuffer;
viz::OutputSurfaceFrame m_frame;
bool m_readyToUpdate = false;
+ bool m_requiresAlpha;
scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner;
-
-#if QT_CONFIG(webengine_vulkan)
- VkImage m_importedImage = VK_NULL_HANDLE;
- VkDeviceMemory m_importedImageMemory = VK_NULL_HANDLE;
-#endif // QT_CONFIG(webengine_vulkan)
};
} // namespace QtWebEngineCore
diff --git a/src/core/compositor/display_software_output_surface.cpp b/src/core/compositor/display_software_output_surface.cpp
index 2277dfea3..2c208ca57 100644
--- a/src/core/compositor/display_software_output_surface.cpp
+++ b/src/core/compositor/display_software_output_surface.cpp
@@ -4,15 +4,15 @@
#include "display_software_output_surface.h"
#include "compositor.h"
-#include "render_widget_host_view_qt_delegate.h"
#include "type_conversion.h"
-#include "base/threading/thread_task_runner_handle.h"
+#include "base/task/single_thread_task_runner.h"
#include "components/viz/service/display/display.h"
#include "components/viz/service/display/output_surface_frame.h"
#include <QMutex>
#include <QPainter>
+#include <QQuickWindow>
namespace QtWebEngineCore {
@@ -20,31 +20,35 @@ class DisplaySoftwareOutputSurface::Device final : public viz::SoftwareOutputDev
public Compositor
{
public:
- Device();
+ Device(bool requiresAlpha);
// Overridden from viz::SoftwareOutputDevice.
void Resize(const gfx::Size &sizeInPixels, float devicePixelRatio) override;
- void OnSwapBuffers(SwapBuffersCallback swap_ack_callback) override;
+ void OnSwapBuffers(SwapBuffersCallback swap_ack_callback, gfx::FrameData data) override;
// Overridden from Compositor.
void swapFrame() override;
- QImage image() override;
+ QSGTexture *texture(QQuickWindow *win, uint32_t) override;
+ bool textureIsFlipped() override;
float devicePixelRatio() override;
QSize size() override;
- bool hasAlphaChannel() override;
+ bool requiresAlphaChannel() override;
private:
mutable QMutex m_mutex;
float m_devicePixelRatio = 1.0;
+ bool m_requiresAlpha;
scoped_refptr<base::SingleThreadTaskRunner> m_taskRunner;
SwapBuffersCallback m_swapCompletionCallback;
QImage m_image;
float m_imageDevicePixelRatio = 1.0;
};
-DisplaySoftwareOutputSurface::Device::Device()
+DisplaySoftwareOutputSurface::Device::Device(bool requiresAlpha)
: Compositor(Type::Software)
-{}
+ , m_requiresAlpha(requiresAlpha)
+{
+}
void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels, float devicePixelRatio)
{
@@ -52,14 +56,14 @@ void DisplaySoftwareOutputSurface::Device::Resize(const gfx::Size &sizeInPixels,
return;
m_devicePixelRatio = devicePixelRatio;
viewport_pixel_size_ = sizeInPixels;
- surface_ = SkSurface::MakeRaster(SkImageInfo::MakeN32Premul(sizeInPixels.width(), sizeInPixels.height()));
+ surface_ = SkSurfaces::Raster(SkImageInfo::MakeN32Premul(sizeInPixels.width(), sizeInPixels.height()));
}
-void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(SwapBuffersCallback swap_ack_callback)
+void DisplaySoftwareOutputSurface::Device::OnSwapBuffers(SwapBuffersCallback swap_ack_callback, gfx::FrameData data)
{
{ // MEMO don't hold a lock together with an 'observer', as the call from Qt's scene graph may come at the same time
QMutexLocker locker(&m_mutex);
- m_taskRunner = base::ThreadTaskRunnerHandle::Get();
+ m_taskRunner = base::SingleThreadTaskRunner::GetCurrentDefault();
m_swapCompletionCallback = std::move(swap_ack_callback);
}
@@ -107,9 +111,14 @@ void DisplaySoftwareOutputSurface::Device::swapFrame()
m_taskRunner.reset();
}
-QImage DisplaySoftwareOutputSurface::Device::image()
+QSGTexture *DisplaySoftwareOutputSurface::Device::texture(QQuickWindow *win, uint32_t)
+{
+ return win->createTextureFromImage(m_image);
+}
+
+bool DisplaySoftwareOutputSurface::Device::textureIsFlipped()
{
- return m_image;
+ return false;
}
float DisplaySoftwareOutputSurface::Device::devicePixelRatio()
@@ -122,13 +131,13 @@ QSize DisplaySoftwareOutputSurface::Device::size()
return m_image.size();
}
-bool DisplaySoftwareOutputSurface::Device::hasAlphaChannel()
+bool DisplaySoftwareOutputSurface::Device::requiresAlphaChannel()
{
- return m_image.format() == QImage::Format_ARGB32_Premultiplied;
+ return m_requiresAlpha;
}
-DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface()
- : SoftwareOutputSurface(std::make_unique<Device>())
+DisplaySoftwareOutputSurface::DisplaySoftwareOutputSurface(bool requiresAlpha)
+ : SoftwareOutputSurface(std::make_unique<Device>(requiresAlpha))
{}
DisplaySoftwareOutputSurface::~DisplaySoftwareOutputSurface() {}
diff --git a/src/core/compositor/display_software_output_surface.h b/src/core/compositor/display_software_output_surface.h
index 5bb4e77c3..d23664d56 100644
--- a/src/core/compositor/display_software_output_surface.h
+++ b/src/core/compositor/display_software_output_surface.h
@@ -11,7 +11,7 @@ namespace QtWebEngineCore {
class DisplaySoftwareOutputSurface final : public viz::SoftwareOutputSurface
{
public:
- DisplaySoftwareOutputSurface();
+ DisplaySoftwareOutputSurface(bool requiresAlpha);
~DisplaySoftwareOutputSurface() override;
// Overridden from viz::OutputSurface.
diff --git a/src/core/compositor/native_skia_output_device.cpp b/src/core/compositor/native_skia_output_device.cpp
new file mode 100644
index 000000000..708692df7
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device.cpp
@@ -0,0 +1,422 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "native_skia_output_device.h"
+
+#include "type_conversion.h"
+
+#include "components/viz/common/resources/shared_image_format.h"
+#include "components/viz/common/resources/shared_image_format_utils.h"
+#include "components/viz/service/display_embedder/skia_output_surface_dependency.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/shared_image_usage.h"
+#include "gpu/command_buffer/service/shared_image/shared_image_factory.h"
+#include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
+#include "gpu/command_buffer/service/skia_utils.h"
+#include "third_party/skia/include/gpu/GrDirectContext.h"
+#include "third_party/skia/include/core/SkSurfaceProps.h"
+#include "ui/gfx/native_pixmap.h"
+#include "ui/gfx/gpu_fence.h"
+#include "ui/gl/gl_fence.h"
+
+#if defined(USE_OZONE)
+#include "ui/ozone/public/ozone_platform.h"
+#endif
+
+namespace QtWebEngineCore {
+
+namespace {
+
+// Helper function for moving a GpuFence from a fence handle to a unique_ptr.
+std::unique_ptr<gfx::GpuFence> TakeGpuFence(gfx::GpuFenceHandle fence)
+{
+ return fence.is_null() ? nullptr : std::make_unique<gfx::GpuFence>(std::move(fence));
+}
+
+} // namespace
+
+NativeSkiaOutputDevice::NativeSkiaOutputDevice(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback)
+ : SkiaOutputDevice(contextState->gr_context(), contextState->graphite_context(), memoryTracker,
+ didSwapBufferCompleteCallback)
+ , Compositor(Type::Native)
+ , m_contextState(contextState)
+ , m_requiresAlpha(requiresAlpha)
+ , m_factory(shared_image_factory)
+ , m_representationFactory(shared_image_representation_factory)
+ , m_deps(dependency)
+{
+ capabilities_.uses_default_gl_framebuffer = false;
+ capabilities_.supports_surfaceless = true;
+ capabilities_.output_surface_origin = gfx::SurfaceOrigin::kTopLeft;
+ capabilities_.preserve_buffer_content = true;
+ capabilities_.only_invalidates_damage_rect = false;
+
+#if defined(USE_OZONE)
+ m_isNativeBufferSupported = ui::OzonePlatform::GetInstance()
+ ->GetPlatformRuntimeProperties()
+ .supports_native_pixmaps;
+#endif
+}
+
+NativeSkiaOutputDevice::~NativeSkiaOutputDevice()
+{
+}
+
+void NativeSkiaOutputDevice::SetFrameSinkId(const viz::FrameSinkId &id)
+{
+ bind(id);
+}
+
+bool NativeSkiaOutputDevice::Reshape(const SkImageInfo &image_info,
+ const gfx::ColorSpace &colorSpace,
+ int sample_count,
+ float device_scale_factor,
+ gfx::OverlayTransform transform)
+{
+ m_shape = Shape{image_info, device_scale_factor, colorSpace, sample_count};
+ DCHECK_EQ(transform, gfx::OVERLAY_TRANSFORM_NONE);
+ return true;
+}
+
+void NativeSkiaOutputDevice::Present(const absl::optional<gfx::Rect> &update_rect,
+ BufferPresentedCallback feedback,
+ viz::OutputSurfaceFrame frame)
+{
+ DCHECK(m_backBuffer);
+
+ StartSwapBuffers(std::move(feedback));
+ m_frame = std::move(frame);
+ {
+ QMutexLocker locker(&m_mutex);
+ m_backBuffer->createFence();
+ m_gpuTaskRunner = base::SingleThreadTaskRunner::GetCurrentDefault();
+ std::swap(m_middleBuffer, m_backBuffer);
+ m_readyToUpdate = true;
+ }
+
+ if (auto obs = observer())
+ obs->readyToSwap();
+}
+
+void NativeSkiaOutputDevice::EnsureBackbuffer()
+{
+}
+
+void NativeSkiaOutputDevice::DiscardBackbuffer()
+{
+}
+
+SkSurface *NativeSkiaOutputDevice::BeginPaint(std::vector<GrBackendSemaphore> *end_semaphores)
+{
+ {
+ QMutexLocker locker(&m_mutex);
+ if (!m_backBuffer || m_backBuffer->shape() != m_shape) {
+ m_backBuffer = std::make_unique<Buffer>(this);
+ if (!m_backBuffer->initialize())
+ return nullptr;
+ }
+ }
+ auto surface = m_backBuffer->beginWriteSkia();
+ *end_semaphores = m_backBuffer->takeEndWriteSkiaSemaphores();
+ return surface;
+}
+
+void NativeSkiaOutputDevice::EndPaint()
+{
+ m_backBuffer->endWriteSkia(true);
+}
+
+void NativeSkiaOutputDevice::swapFrame()
+{
+ QMutexLocker locker(&m_mutex);
+ if (m_readyToUpdate) {
+ std::swap(m_frontBuffer, m_middleBuffer);
+ m_gpuTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&NativeSkiaOutputDevice::SwapBuffersFinished,
+ base::Unretained(this)));
+ m_readyToUpdate = false;
+ if (m_frontBuffer) {
+ m_readyWithTexture = true;
+ m_frontBuffer->beginPresent();
+ }
+ if (m_middleBuffer)
+ m_middleBuffer->freeTexture();
+ m_gpuTaskRunner.reset();
+ }
+}
+
+void NativeSkiaOutputDevice::waitForTexture()
+{
+ if (m_readyWithTexture)
+ m_frontBuffer->consumeFence();
+}
+
+void NativeSkiaOutputDevice::releaseTexture()
+{
+ if (m_readyWithTexture) {
+ m_frontBuffer->endPresent();
+ m_readyWithTexture = false;
+ }
+}
+
+void NativeSkiaOutputDevice::releaseResources()
+{
+ if (m_frontBuffer)
+ m_frontBuffer->freeTexture();
+}
+
+bool NativeSkiaOutputDevice::textureIsFlipped()
+{
+ return false;
+}
+
+QSize NativeSkiaOutputDevice::size()
+{
+ return m_frontBuffer ? toQt(m_frontBuffer->shape().imageInfo.dimensions()) : QSize();
+}
+
+bool NativeSkiaOutputDevice::requiresAlphaChannel()
+{
+ return m_requiresAlpha;
+}
+
+float NativeSkiaOutputDevice::devicePixelRatio()
+{
+ return m_frontBuffer ? m_frontBuffer->shape().devicePixelRatio : 1;
+}
+
+void NativeSkiaOutputDevice::SwapBuffersFinished()
+{
+ {
+ QMutexLocker locker(&m_mutex);
+ std::swap(m_backBuffer, m_middleBuffer);
+ }
+
+ FinishSwapBuffers(gfx::SwapCompletionResult(gfx::SwapResult::SWAP_ACK),
+ gfx::Size(m_shape.imageInfo.width(), m_shape.imageInfo.height()),
+ std::move(m_frame));
+}
+
+NativeSkiaOutputDevice::Buffer::Buffer(NativeSkiaOutputDevice *parent)
+ : m_parent(parent), m_shape(m_parent->m_shape)
+{
+}
+
+NativeSkiaOutputDevice::Buffer::~Buffer()
+{
+ if (m_scopedSkiaWriteAccess)
+ endWriteSkia(false);
+
+ if (!m_mailbox.IsZero())
+ m_parent->m_factory->DestroySharedImage(m_mailbox);
+}
+
+// The following Buffer methods are based on
+// components/viz/service/display_embedder/output_presenter.cc: Copyright 2020 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+bool NativeSkiaOutputDevice::Buffer::initialize()
+{
+ static const uint32_t kDefaultSharedImageUsage = gpu::SHARED_IMAGE_USAGE_SCANOUT
+ | gpu::SHARED_IMAGE_USAGE_DISPLAY_READ | gpu::SHARED_IMAGE_USAGE_DISPLAY_WRITE
+ | gpu::SHARED_IMAGE_USAGE_GLES2_FRAMEBUFFER_HINT;
+ auto mailbox = gpu::Mailbox::GenerateForSharedImage();
+
+ SkColorType skColorType = m_shape.imageInfo.colorType();
+ if (!m_parent->m_factory->CreateSharedImage(
+ mailbox, viz::SkColorTypeToSinglePlaneSharedImageFormat(skColorType),
+ { m_shape.imageInfo.width(), m_shape.imageInfo.height() }, m_shape.colorSpace,
+ kTopLeft_GrSurfaceOrigin, kPremul_SkAlphaType, m_parent->m_deps->GetSurfaceHandle(),
+ kDefaultSharedImageUsage, "QWE_SharedImageBuffer")) {
+ LOG(ERROR) << "CreateSharedImage failed.";
+ return false;
+ }
+ m_mailbox = mailbox;
+
+ m_skiaRepresentation =
+ m_parent->m_representationFactory->ProduceSkia(m_mailbox, m_parent->m_contextState);
+ if (!m_skiaRepresentation) {
+ LOG(ERROR) << "ProduceSkia() failed.";
+ return false;
+ }
+
+ if (m_parent->m_isNativeBufferSupported) {
+ m_overlayRepresentation = m_parent->m_representationFactory->ProduceOverlay(m_mailbox);
+ if (!m_overlayRepresentation) {
+ LOG(ERROR) << "ProduceOverlay() failed";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+SkSurface *NativeSkiaOutputDevice::Buffer::beginWriteSkia()
+{
+ DCHECK(!m_scopedSkiaWriteAccess);
+ DCHECK(!m_presentCount);
+ DCHECK(m_endSemaphores.empty());
+
+ std::vector<GrBackendSemaphore> beginSemaphores;
+ SkSurfaceProps surface_props{ 0, kUnknown_SkPixelGeometry };
+
+ // Buffer queue is internal to GPU proc and handles texture initialization,
+ // so allow uncleared access.
+ m_scopedSkiaWriteAccess = m_skiaRepresentation->BeginScopedWriteAccess(
+ m_shape.sampleCount, surface_props, &beginSemaphores, &m_endSemaphores,
+ gpu::SharedImageRepresentation::AllowUnclearedAccess::kYes);
+ DCHECK(m_scopedSkiaWriteAccess);
+ if (!beginSemaphores.empty()) {
+ m_scopedSkiaWriteAccess->surface()->wait(beginSemaphores.size(), beginSemaphores.data(),
+ /*deleteSemaphoresAfterWait=*/false);
+ }
+ return m_scopedSkiaWriteAccess->surface();
+}
+
+void NativeSkiaOutputDevice::Buffer::endWriteSkia(bool force_flush)
+{
+ // The Flush now takes place in finishPaintCurrentBuffer on the CPU side.
+ // check if end_semaphores is not empty then flush here
+ DCHECK(m_scopedSkiaWriteAccess);
+ if (!m_endSemaphores.empty() || force_flush) {
+ GrFlushInfo flush_info = {};
+ flush_info.fNumSemaphores = m_endSemaphores.size();
+ flush_info.fSignalSemaphores = m_endSemaphores.data();
+ auto *direct_context =
+ m_scopedSkiaWriteAccess->surface()->recordingContext()->asDirectContext();
+ DCHECK(direct_context);
+ direct_context->flush(m_scopedSkiaWriteAccess->surface(), {});
+ m_scopedSkiaWriteAccess->ApplyBackendSurfaceEndState();
+ direct_context->flush(m_scopedSkiaWriteAccess->surface(), flush_info, nullptr);
+ direct_context->submit();
+ }
+ m_scopedSkiaWriteAccess.reset();
+ m_endSemaphores.clear();
+
+ // SkiaRenderer always draws the full frame.
+ m_skiaRepresentation->SetCleared();
+}
+
+std::vector<GrBackendSemaphore> NativeSkiaOutputDevice::Buffer::takeEndWriteSkiaSemaphores()
+{
+ return std::exchange(m_endSemaphores, {});
+}
+
+void NativeSkiaOutputDevice::Buffer::createSkImageOnGPUThread()
+{
+ if (!m_scopedSkiaReadAccess) {
+ m_skImageMutex.unlock();
+ return;
+ }
+
+ m_cachedSkImage = m_scopedSkiaReadAccess->CreateSkImage(m_parent->m_contextState.get());
+ m_skImageMutex.unlock();
+ if (!m_cachedSkImage)
+ qWarning("SKIA: Failed to create SkImage.");
+}
+
+void NativeSkiaOutputDevice::Buffer::beginPresent()
+{
+ if (++m_presentCount != 1) {
+ DCHECK(m_scopedOverlayReadAccess || m_scopedSkiaReadAccess);
+ return;
+ }
+
+ DCHECK(!m_scopedSkiaWriteAccess);
+ DCHECK(!m_scopedOverlayReadAccess && !m_scopedSkiaReadAccess);
+
+ if (m_overlayRepresentation) {
+ m_scopedOverlayReadAccess = m_overlayRepresentation->BeginScopedReadAccess();
+ DCHECK(m_scopedOverlayReadAccess);
+ m_acquireFence = TakeGpuFence(m_scopedOverlayReadAccess->TakeAcquireFence());
+ } else {
+ DCHECK(m_skiaRepresentation);
+ std::vector<GrBackendSemaphore> beginSemaphores;
+ m_scopedSkiaReadAccess =
+ m_skiaRepresentation->BeginScopedReadAccess(&beginSemaphores, nullptr);
+ DCHECK(m_scopedSkiaReadAccess);
+ if (!beginSemaphores.empty())
+ qWarning("SKIA: Unexpected semaphores while reading texture, wait is not implemented.");
+
+ m_skImageMutex.tryLock();
+ m_parent->m_gpuTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&NativeSkiaOutputDevice::Buffer::createSkImageOnGPUThread,
+ base::Unretained(this)));
+ }
+}
+
+void NativeSkiaOutputDevice::Buffer::endPresent()
+{
+ if (!m_presentCount)
+ return;
+ DCHECK(m_scopedOverlayReadAccess || m_scopedSkiaReadAccess);
+ if (--m_presentCount)
+ return;
+
+ if (m_scopedOverlayReadAccess) {
+ DCHECK(!m_scopedSkiaReadAccess);
+ m_scopedOverlayReadAccess.reset();
+ } else if (m_scopedSkiaReadAccess) {
+ DCHECK(!m_scopedOverlayReadAccess);
+ QMutexLocker locker(&m_skImageMutex);
+ m_scopedSkiaReadAccess.reset();
+ }
+}
+
+void NativeSkiaOutputDevice::Buffer::freeTexture()
+{
+ if (textureCleanupCallback) {
+ textureCleanupCallback();
+ textureCleanupCallback = nullptr;
+ }
+}
+
+void NativeSkiaOutputDevice::Buffer::createFence()
+{
+ // For some reason we still need to create this, but we do not need to wait on it.
+ if (m_parent->m_contextState->gr_context_type() == gpu::GrContextType::kGL)
+ m_fence = gl::GLFence::Create();
+}
+
+void NativeSkiaOutputDevice::Buffer::consumeFence()
+{
+ if (m_acquireFence) {
+ m_acquireFence->Wait();
+ m_acquireFence.reset();
+ }
+}
+
+sk_sp<SkImage> NativeSkiaOutputDevice::Buffer::skImage()
+{
+ QMutexLocker locker(&m_skImageMutex);
+ return m_cachedSkImage;
+}
+#if defined(USE_OZONE)
+scoped_refptr<gfx::NativePixmap> NativeSkiaOutputDevice::Buffer::nativePixmap()
+{
+ DCHECK(m_presentCount);
+ if (!m_scopedOverlayReadAccess)
+ return nullptr;
+
+ return m_scopedOverlayReadAccess->GetNativePixmap();
+}
+#elif defined(Q_OS_WIN)
+absl::optional<gl::DCLayerOverlayImage> NativeSkiaOutputDevice::Buffer::overlayImage() const
+{
+ DCHECK(m_presentCount);
+ return m_scopedOverlayReadAccess->GetDCLayerOverlayImage();
+}
+#elif defined(Q_OS_MACOS)
+gfx::ScopedIOSurface NativeSkiaOutputDevice::Buffer::ioSurface() const
+{
+ DCHECK(m_presentCount);
+ return m_scopedOverlayReadAccess->GetIOSurface();
+}
+#endif
+
+} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device.h b/src/core/compositor/native_skia_output_device.h
new file mode 100644
index 000000000..2c35cef77
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device.h
@@ -0,0 +1,183 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NATIVE_SKIA_OUTPUT_DEVICE_H
+#define NATIVE_SKIA_OUTPUT_DEVICE_H
+
+#include "compositor.h"
+
+#include "base/task/single_thread_task_runner.h"
+#include "components/viz/service/display_embedder/skia_output_device.h"
+#include "gpu/command_buffer/service/shared_context_state.h"
+#include "gpu/command_buffer/service/shared_image/shared_image_representation.h"
+#include "gpu/config/gpu_preferences.h"
+
+#include <QMutex>
+
+#if defined(Q_OS_WIN)
+#include "ui/gl/dc_layer_overlay_image.h"
+#endif
+
+#if defined(Q_OS_MACOS)
+#include "ui/gfx/mac/io_surface.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+class QQuickWindow;
+QT_END_NAMESPACE
+
+namespace gl {
+class GLFence;
+}
+
+namespace gfx {
+class GpuFence;
+class NativePixmap;
+}
+
+namespace gpu {
+class SharedImageFactory;
+class SharedImageRepresentationFactory;
+}
+
+namespace viz {
+class SkiaOutputSurfaceDependency;
+}
+
+namespace QtWebEngineCore {
+
+class NativeSkiaOutputDevice : public viz::SkiaOutputDevice, public Compositor
+{
+public:
+ NativeSkiaOutputDevice(scoped_refptr<gpu::SharedContextState> contextState,
+ bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker,
+ viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback);
+ ~NativeSkiaOutputDevice() override;
+
+ // Overridden from SkiaOutputDevice.
+ void SetFrameSinkId(const viz::FrameSinkId &frame_sink_id) override;
+ bool Reshape(const SkImageInfo &image_info,
+ const gfx::ColorSpace &color_space,
+ int sample_count,
+ float device_scale_factor,
+ gfx::OverlayTransform transform) override;
+ void Present(const absl::optional<gfx::Rect>& update_rect,
+ BufferPresentedCallback feedback,
+ viz::OutputSurfaceFrame frame) override;
+ void EnsureBackbuffer() override;
+ void DiscardBackbuffer() override;
+ SkSurface *BeginPaint(std::vector<GrBackendSemaphore> *semaphores) override;
+ void EndPaint() override;
+
+ // Overridden from Compositor.
+ void swapFrame() override;
+ void waitForTexture() override;
+ void releaseTexture() override;
+ void releaseResources() override;
+ bool textureIsFlipped() override;
+ QSize size() override;
+ bool requiresAlphaChannel() override;
+ float devicePixelRatio() override;
+
+protected:
+ struct Shape
+ {
+ SkImageInfo imageInfo;
+ float devicePixelRatio;
+ gfx::ColorSpace colorSpace;
+ int sampleCount;
+
+ bool operator==(const Shape &that) const
+ {
+ return (imageInfo == that.imageInfo &&
+ devicePixelRatio == that.devicePixelRatio &&
+ colorSpace == that.colorSpace &&
+ sampleCount == that.sampleCount);
+ }
+ bool operator!=(const Shape &that) const { return !(*this == that); }
+ };
+
+ class Buffer
+ {
+ public:
+ Buffer(NativeSkiaOutputDevice *parent);
+ ~Buffer();
+
+ bool initialize();
+ SkSurface *beginWriteSkia();
+ void endWriteSkia(bool force_flush);
+ std::vector<GrBackendSemaphore> takeEndWriteSkiaSemaphores();
+ void beginPresent();
+ void endPresent();
+ void freeTexture();
+ void createFence();
+ void consumeFence();
+
+ sk_sp<SkImage> skImage();
+#if defined(USE_OZONE)
+ scoped_refptr<gfx::NativePixmap> nativePixmap();
+#elif defined(Q_OS_WIN)
+ absl::optional<gl::DCLayerOverlayImage> overlayImage() const;
+#elif defined(Q_OS_MACOS)
+ gfx::ScopedIOSurface ioSurface() const;
+#endif
+
+ const Shape &shape() const { return m_shape; }
+ viz::SharedImageFormat sharedImageFormat() const { return m_skiaRepresentation->format(); }
+
+ std::function<void()> textureCleanupCallback;
+
+ private:
+ void createSkImageOnGPUThread();
+
+ NativeSkiaOutputDevice *m_parent;
+ Shape m_shape;
+ uint64_t m_estimatedSize = 0; // FIXME: estimate size
+ std::unique_ptr<gfx::GpuFence> m_acquireFence;
+ std::unique_ptr<gl::GLFence> m_fence;
+ gpu::Mailbox m_mailbox;
+ std::unique_ptr<gpu::SkiaImageRepresentation> m_skiaRepresentation;
+ std::unique_ptr<gpu::SkiaImageRepresentation::ScopedWriteAccess> m_scopedSkiaWriteAccess;
+ std::unique_ptr<gpu::SkiaImageRepresentation::ScopedReadAccess> m_scopedSkiaReadAccess;
+ std::unique_ptr<gpu::OverlayImageRepresentation> m_overlayRepresentation;
+ std::unique_ptr<gpu::OverlayImageRepresentation::ScopedReadAccess>
+ m_scopedOverlayReadAccess;
+ std::vector<GrBackendSemaphore> m_endSemaphores;
+ int m_presentCount = 0;
+
+ mutable QMutex m_skImageMutex;
+ sk_sp<SkImage> m_cachedSkImage;
+ };
+
+protected:
+ scoped_refptr<gpu::SharedContextState> m_contextState;
+ std::unique_ptr<Buffer> m_frontBuffer;
+ bool m_readyWithTexture = false;
+ bool m_isNativeBufferSupported = true;
+
+private:
+ friend class NativeSkiaOutputDevice::Buffer;
+
+ void SwapBuffersFinished();
+
+ mutable QMutex m_mutex;
+ Shape m_shape;
+ std::unique_ptr<Buffer> m_middleBuffer;
+ std::unique_ptr<Buffer> m_backBuffer;
+ viz::OutputSurfaceFrame m_frame;
+ bool m_readyToUpdate = false;
+ bool m_requiresAlpha;
+ scoped_refptr<base::SingleThreadTaskRunner> m_gpuTaskRunner;
+
+ const raw_ptr<gpu::SharedImageFactory> m_factory;
+ const raw_ptr<gpu::SharedImageRepresentationFactory> m_representationFactory;
+ const raw_ptr<viz::SkiaOutputSurfaceDependency> m_deps;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // !NATIVE_SKIA_OUTPUT_DEVICE_H
diff --git a/src/core/compositor/native_skia_output_device_direct3d11.cpp b/src/core/compositor/native_skia_output_device_direct3d11.cpp
new file mode 100644
index 000000000..352fa9f92
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_direct3d11.cpp
@@ -0,0 +1,88 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "native_skia_output_device_direct3d11.h"
+
+#include <QtCore/private/qsystemerror_p.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qsgtexture.h>
+
+#include <d3d11_1.h>
+
+namespace QtWebEngineCore {
+
+NativeSkiaOutputDeviceDirect3D11::NativeSkiaOutputDeviceDirect3D11(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback)
+ : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency,
+ shared_image_factory, shared_image_representation_factory,
+ didSwapBufferCompleteCallback)
+{
+ SkColorType skColorType = kRGBA_8888_SkColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType;
+}
+
+NativeSkiaOutputDeviceDirect3D11::~NativeSkiaOutputDeviceDirect3D11() { }
+
+QSGTexture *NativeSkiaOutputDeviceDirect3D11::texture(QQuickWindow *win, uint32_t textureOptions)
+{
+ if (!m_frontBuffer || !m_readyWithTexture)
+ return nullptr;
+
+ absl::optional<gl::DCLayerOverlayImage> overlayImage = m_frontBuffer->overlayImage();
+ if (!overlayImage) {
+ qWarning("No overlay image.");
+ return nullptr;
+ }
+
+ QSGRendererInterface *ri = win->rendererInterface();
+
+ HRESULT status = S_OK;
+ HANDLE sharedHandle = nullptr;
+ IDXGIResource1 *resource = nullptr;
+ if (!overlayImage->nv12_texture()) {
+ qWarning("No D3D texture.");
+ return nullptr;
+ }
+ status = overlayImage->nv12_texture()->QueryInterface(__uuidof(IDXGIResource1),
+ (void **)&resource);
+ Q_ASSERT(status == S_OK);
+ status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle);
+ Q_ASSERT(status == S_OK);
+ Q_ASSERT(sharedHandle);
+
+ // Pass texture between two D3D devices:
+ ID3D11Device1 *device = static_cast<ID3D11Device1 *>(
+ ri->getResource(win, QSGRendererInterface::DeviceResource));
+
+ ID3D11Texture2D *qtTexture;
+ status = device->OpenSharedResource1(sharedHandle, __uuidof(ID3D11Texture2D),
+ (void **)&qtTexture);
+ if (status != S_OK) {
+ qWarning("Failed to share D3D11 texture (%s). This will result in failed rendering. Report "
+ "the bug, and try restarting with QTWEBENGINE_CHROMIUM_FLAGS=--disble-gpu",
+ qPrintable(QSystemError::windowsComString(status)));
+ ::CloseHandle(sharedHandle);
+ return nullptr;
+ }
+
+ Q_ASSERT(qtTexture);
+ QQuickWindow::CreateTextureOptions texOpts(textureOptions);
+ QSGTexture *texture =
+ QNativeInterface::QSGD3D11Texture::fromNative(qtTexture, win, size(), texOpts);
+
+ m_frontBuffer->textureCleanupCallback = [qtTexture, sharedHandle]() {
+ qtTexture->Release();
+ ::CloseHandle(sharedHandle);
+ };
+
+ return texture;
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device_direct3d11.h b/src/core/compositor/native_skia_output_device_direct3d11.h
new file mode 100644
index 000000000..33cf1bcd6
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_direct3d11.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NATIVE_SKIA_OUTPUT_DEVICE_DIRECT3D11_H
+#define NATIVE_SKIA_OUTPUT_DEVICE_DIRECT3D11_H
+
+#include "native_skia_output_device.h"
+
+namespace QtWebEngineCore {
+
+class NativeSkiaOutputDeviceDirect3D11 final : public NativeSkiaOutputDevice
+{
+public:
+ NativeSkiaOutputDeviceDirect3D11(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback);
+ ~NativeSkiaOutputDeviceDirect3D11() override;
+
+ // Overridden from Compositor:
+ QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // NATIVE_SKIA_OUTPUT_DEVICE_DIRECT3D11_H
diff --git a/src/core/compositor/native_skia_output_device_mac.mm b/src/core/compositor/native_skia_output_device_mac.mm
new file mode 100644
index 000000000..bf21ef8d7
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_mac.mm
@@ -0,0 +1,97 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// This is a workaround to be able to include Qt headers without
+// "redefinition of 'NSString' as different kind of symbol" errors.
+// TODO: Remove this when namespace ambiguity issues are fixed properly,
+// see get_forward_declaration_macro() in cmake/Functions.cmake
+#undef Q_FORWARD_DECLARE_OBJC_CLASS
+
+#import <AppKit/AppKit.h>
+#import <IOSurface/IOSurface.h>
+#import <Metal/Metal.h>
+
+#include <QtGui/qtguiglobal.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qsgrendererinterface.h>
+#include <QtQuick/qsgtexture.h>
+
+#if QT_CONFIG(opengl)
+#include <OpenGL/OpenGL.h>
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglextrafunctions.h>
+#include <QtOpenGL/qopengltextureblitter.h>
+#include <QtOpenGL/qopenglframebufferobject.h>
+#endif
+
+namespace QtWebEngineCore {
+
+QSGTexture *makeMetalTexture(QQuickWindow *win, IOSurfaceRef ioSurface, uint ioSurfacePlane,
+ const QSize &size, QQuickWindow::CreateTextureOptions texOpts)
+{
+ auto desc = [MTLTextureDescriptor texture2DDescriptorWithPixelFormat:MTLPixelFormatBGRA8Unorm
+ width:size.width()
+ height:size.height()
+ mipmapped:false];
+
+ QSGRendererInterface *ri = win->rendererInterface();
+ auto device = (__bridge id<MTLDevice>)(ri->getResource(win, QSGRendererInterface::DeviceResource));
+ id<MTLTexture> texture = [device newTextureWithDescriptor:desc
+ iosurface:ioSurface
+ plane:ioSurfacePlane];
+ return QNativeInterface::QSGMetalTexture::fromNative(texture, win, size, texOpts);
+}
+
+void releaseMetalTexture(void *texture)
+{
+ [static_cast<id<MTLTexture>>(texture) release];
+}
+
+#if QT_CONFIG(opengl)
+uint32_t makeCGLTexture(QQuickWindow *win, IOSurfaceRef ioSurface, const QSize &size)
+{
+ const int width = size.width();
+ const int height = size.height();
+
+ auto glContext = QOpenGLContext::currentContext();
+ auto glFun = glContext->extraFunctions();
+ auto nscontext = glContext->nativeInterface<QNativeInterface::QCocoaGLContext>()->nativeContext();
+ CGLContextObj cglContext = [nscontext CGLContextObj];
+
+ win->beginExternalCommands();
+ // Bind the IO surface to a texture
+ GLuint glTexture;
+ glFun->glGenTextures(1, &glTexture);
+ glFun->glBindTexture(GL_TEXTURE_RECTANGLE_ARB, glTexture);
+ CGLTexImageIOSurface2D(cglContext, GL_TEXTURE_RECTANGLE_ARB, GL_RGBA, width, height, GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV, ioSurface, 0);
+ glFun->glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ glFun->glViewport(0, 0, width, height);
+
+ // The bound IO surface is a weird dynamic bind, so take a snapshot of it to a normal texture
+ {
+ QOpenGLFramebufferObject fbo(width, height, GL_TEXTURE_2D);
+ auto success = fbo.bind();
+ Q_ASSERT(success);
+
+ QOpenGLTextureBlitter blitter;
+ success = blitter.create();
+ Q_ASSERT(success);
+ glFun->glDisable(GL_BLEND);
+ glFun->glDisable(GL_SCISSOR_TEST);
+ blitter.bind(GL_TEXTURE_RECTANGLE_ARB);
+ blitter.blit(glTexture, {}, QOpenGLTextureBlitter::OriginBottomLeft);
+ blitter.release();
+ blitter.destroy();
+
+ glFun->glDeleteTextures(1, &glTexture);
+ glTexture = fbo.takeTexture();
+ fbo.release();
+ }
+ win->endExternalCommands();
+
+ return glTexture;
+}
+#endif // QT_CONFIG(opengl)
+
+} // namespace
diff --git a/src/core/compositor/native_skia_output_device_metal.cpp b/src/core/compositor/native_skia_output_device_metal.cpp
new file mode 100644
index 000000000..a9d6e4fd5
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_metal.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "native_skia_output_device_metal.h"
+
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qsgtexture.h>
+
+namespace QtWebEngineCore {
+
+NativeSkiaOutputDeviceMetal::NativeSkiaOutputDeviceMetal(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback)
+ : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency,
+ shared_image_factory, shared_image_representation_factory,
+ didSwapBufferCompleteCallback)
+{
+ SkColorType skColorType = kRGBA_8888_SkColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType;
+}
+
+NativeSkiaOutputDeviceMetal::~NativeSkiaOutputDeviceMetal() { }
+
+QSGTexture *makeMetalTexture(QQuickWindow *win, IOSurfaceRef ioSurface, uint ioSurfacePlane,
+ const QSize &size, QQuickWindow::CreateTextureOptions texOpts);
+void releaseMetalTexture(void *texture);
+
+QSGTexture *NativeSkiaOutputDeviceMetal::texture(QQuickWindow *win, uint32_t textureOptions)
+{
+ if (!m_frontBuffer || !m_readyWithTexture)
+ return nullptr;
+
+ gfx::ScopedIOSurface ioSurface = m_frontBuffer->ioSurface();
+ if (!ioSurface) {
+ qWarning("No IOSurface.");
+ return nullptr;
+ }
+
+ // This is a workaround to not to release metal texture too early.
+ // In RHI, QMetalTexture wraps MTLTexture. QMetalTexture seems to be only destructed after the
+ // next MTLTexture is imported. The "old" MTLTexture can be still pontentially used by RHI
+ // while QMetalTexture is not destructed. Metal Validation Layer also warns about it.
+ // Delay releasing MTLTexture after the next one is presented.
+ if (m_currentMetalTexture) {
+ m_frontBuffer->textureCleanupCallback = [texture = m_currentMetalTexture]() {
+ releaseMetalTexture(texture);
+ };
+ m_currentMetalTexture = nullptr;
+ }
+
+ QQuickWindow::CreateTextureOptions texOpts(textureOptions);
+ QSGTexture *qsgTexture = makeMetalTexture(win, ioSurface.get(), /* plane */ 0, size(), texOpts);
+
+ auto ni = qsgTexture->nativeInterface<QNativeInterface::QSGMetalTexture>();
+ m_currentMetalTexture = ni->nativeTexture();
+
+ return qsgTexture;
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device_metal.h b/src/core/compositor/native_skia_output_device_metal.h
new file mode 100644
index 000000000..8e8d0fab8
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_metal.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NATIVE_SKIA_OUTPUT_DEVICE_METAL_H
+#define NATIVE_SKIA_OUTPUT_DEVICE_METAL_H
+
+#include "native_skia_output_device.h"
+
+namespace QtWebEngineCore {
+
+class NativeSkiaOutputDeviceMetal final : public NativeSkiaOutputDevice
+{
+public:
+ NativeSkiaOutputDeviceMetal(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback);
+ ~NativeSkiaOutputDeviceMetal() override;
+
+ // Overridden from Compositor:
+ QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override;
+
+private:
+ void *m_currentMetalTexture = nullptr;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // NATIVE_SKIA_OUTPUT_DEVICE_METAL_H
diff --git a/src/core/compositor/native_skia_output_device_opengl.cpp b/src/core/compositor/native_skia_output_device_opengl.cpp
new file mode 100644
index 000000000..058573b9e
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_opengl.cpp
@@ -0,0 +1,86 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "native_skia_output_device_opengl.h"
+
+#include <QtGui/qopenglcontext.h>
+#include <QtGui/qopenglextrafunctions.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qsgtexture.h>
+
+namespace QtWebEngineCore {
+
+NativeSkiaOutputDeviceOpenGL::NativeSkiaOutputDeviceOpenGL(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback)
+ : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency,
+ shared_image_factory, shared_image_representation_factory,
+ didSwapBufferCompleteCallback)
+{
+ SkColorType skColorType = kRGBA_8888_SkColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType;
+}
+
+NativeSkiaOutputDeviceOpenGL::~NativeSkiaOutputDeviceOpenGL() { }
+
+#if defined(Q_OS_MACOS)
+uint32_t makeCGLTexture(QQuickWindow *win, IOSurfaceRef ioSurface, const QSize &size);
+#endif
+
+QSGTexture *NativeSkiaOutputDeviceOpenGL::texture(QQuickWindow *win, uint32_t textureOptions)
+{
+ if (!m_frontBuffer || !m_readyWithTexture)
+ return nullptr;
+
+#if defined(USE_OZONE)
+ scoped_refptr<gfx::NativePixmap> nativePixmap = m_frontBuffer->nativePixmap();
+ if (!nativePixmap) {
+ qWarning("No native pixmap.");
+ return nullptr;
+ }
+#elif defined(Q_OS_WIN)
+ auto overlayImage = m_frontBuffer->overlayImage();
+ if (!overlayImage) {
+ qWarning("No overlay image.");
+ return nullptr;
+ }
+#elif defined(Q_OS_MACOS)
+ gfx::ScopedIOSurface ioSurface = m_frontBuffer->ioSurface();
+ if (!ioSurface) {
+ qWarning("No IOSurface.");
+ return nullptr;
+ }
+#endif
+
+ QQuickWindow::CreateTextureOptions texOpts(textureOptions);
+ QSGTexture *texture = nullptr;
+
+#if defined(USE_OZONE)
+ // TODO(QTBUG-112281): Add ANGLE support to Linux.
+ QT_NOT_YET_IMPLEMENTED
+#elif defined(Q_OS_WIN)
+ // TODO: Add WGL support over ANGLE.
+ QT_NOT_YET_IMPLEMENTED
+#elif defined(Q_OS_MACOS)
+ uint32_t glTexture = makeCGLTexture(win, ioSurface.get(), size());
+ texture = QNativeInterface::QSGOpenGLTexture::fromNative(glTexture, win, size(), texOpts);
+
+ m_frontBuffer->textureCleanupCallback = [glTexture]() {
+ auto *glContext = QOpenGLContext::currentContext();
+ if (!glContext)
+ return;
+ auto glFun = glContext->functions();
+ glFun->glDeleteTextures(1, &glTexture);
+ };
+#endif
+
+ return texture;
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device_opengl.h b/src/core/compositor/native_skia_output_device_opengl.h
new file mode 100644
index 000000000..233f51df9
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_opengl.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NATIVE_SKIA_OUTPUT_DEVICE_OPENGL_H
+#define NATIVE_SKIA_OUTPUT_DEVICE_OPENGL_H
+
+#include "native_skia_output_device.h"
+
+namespace QtWebEngineCore {
+
+class NativeSkiaOutputDeviceOpenGL final : public NativeSkiaOutputDevice
+{
+public:
+ NativeSkiaOutputDeviceOpenGL(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback);
+ ~NativeSkiaOutputDeviceOpenGL() override;
+
+ // Overridden from Compositor:
+ QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // NATIVE_SKIA_OUTPUT_DEVICE_OPENGL_H
diff --git a/src/core/compositor/native_skia_output_device_vulkan.cpp b/src/core/compositor/native_skia_output_device_vulkan.cpp
new file mode 100644
index 000000000..c2ad7a382
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_vulkan.cpp
@@ -0,0 +1,306 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "native_skia_output_device_vulkan.h"
+
+#include "gpu/command_buffer/service/shared_image/shared_image_format_service_utils.h"
+
+#include <QtGui/qvulkaninstance.h>
+#include <QtGui/qvulkanfunctions.h>
+#include <QtQuick/qquickwindow.h>
+#include <QtQuick/qsgtexture.h>
+
+#if defined(USE_OZONE)
+#include "ui/ozone/buildflags.h"
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+// We need to define USE_VULKAN_XCB for proper vulkan function pointers.
+// Avoiding it may lead to call wrong vulkan functions.
+// This is originally defined in chromium/gpu/vulkan/BUILD.gn.
+#define USE_VULKAN_XCB
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
+#include "gpu/vulkan/vulkan_function_pointers.h"
+
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "gpu/vulkan/vulkan_device_queue.h"
+#endif // defined(USE_OZONE)
+
+namespace QtWebEngineCore {
+
+NativeSkiaOutputDeviceVulkan::NativeSkiaOutputDeviceVulkan(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback)
+ : NativeSkiaOutputDevice(contextState, requiresAlpha, memoryTracker, dependency,
+ shared_image_factory, shared_image_representation_factory,
+ didSwapBufferCompleteCallback)
+{
+ SkColorType skColorType = kRGBA_8888_SkColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::RGBX_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRA_8888)] = skColorType;
+ capabilities_.sk_color_types[static_cast<int>(gfx::BufferFormat::BGRX_8888)] = skColorType;
+}
+
+NativeSkiaOutputDeviceVulkan::~NativeSkiaOutputDeviceVulkan() { }
+
+QSGTexture *NativeSkiaOutputDeviceVulkan::texture(QQuickWindow *win, uint32_t textureOptions)
+{
+ if (!m_frontBuffer || !m_readyWithTexture)
+ return nullptr;
+
+#if defined(USE_OZONE)
+ Q_ASSERT(m_contextState->gr_context_type() == gpu::GrContextType::kVulkan);
+
+ GrVkImageInfo vkImageInfo;
+ scoped_refptr<gfx::NativePixmap> nativePixmap = m_frontBuffer->nativePixmap();
+ if (!nativePixmap) {
+ if (m_isNativeBufferSupported) {
+ qWarning("VULKAN: No NativePixmap.");
+ return nullptr;
+ }
+
+ sk_sp<SkImage> skImage = m_frontBuffer->skImage();
+ if (!skImage) {
+ qWarning("VULKAN: No SkImage.");
+ return nullptr;
+ }
+
+ if (!skImage->isTextureBacked()) {
+ qWarning("VULKAN: SkImage is not backed by GPU texture.");
+ return nullptr;
+ }
+
+ GrBackendTexture backendTexture;
+ bool success = SkImages::GetBackendTextureFromImage(skImage, &backendTexture, false);
+ if (!success || !backendTexture.isValid()) {
+ qWarning("VULKAN: Failed to retrieve backend texture from SkImage.");
+ return nullptr;
+ }
+
+ if (backendTexture.backend() != GrBackendApi::kVulkan) {
+ qWarning("VULKAN: Backend texture is not a Vulkan texture.");
+ return nullptr;
+ }
+
+ backendTexture.getVkImageInfo(&vkImageInfo);
+ if (vkImageInfo.fAlloc.fMemory == VK_NULL_HANDLE) {
+ qWarning("VULKAN: Unable to access Vulkan memory.");
+ return nullptr;
+ }
+ }
+#elif defined(Q_OS_WIN)
+ Q_ASSERT(m_contextState->gr_context_type() == gpu::GrContextType::kGL);
+
+ absl::optional<gl::DCLayerOverlayImage> overlayImage = m_frontBuffer->overlayImage();
+ if (!overlayImage) {
+ qWarning("No overlay image.");
+ return nullptr;
+ }
+#endif
+
+ QSGRendererInterface *ri = win->rendererInterface();
+ VkDevice qtVulkanDevice =
+ *static_cast<VkDevice *>(ri->getResource(win, QSGRendererInterface::DeviceResource));
+ VkPhysicalDevice qtPhysicalDevice = *static_cast<VkPhysicalDevice *>(
+ ri->getResource(win, QSGRendererInterface::PhysicalDeviceResource));
+ QVulkanFunctions *f = win->vulkanInstance()->functions();
+ QVulkanDeviceFunctions *df = win->vulkanInstance()->deviceFunctions(qtVulkanDevice);
+
+ VkImageLayout imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+ VkPhysicalDeviceProperties deviceProperties;
+ f->vkGetPhysicalDeviceProperties(qtPhysicalDevice, &deviceProperties);
+ if (deviceProperties.vendorID == 0x10DE) {
+ // FIXME: This is a workaround for Nvidia driver.
+ // The imported image is empty if the initialLayout is not
+ // VK_IMAGE_LAYOUT_PREINITIALIZED.
+ imageLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
+ }
+
+ VkExternalMemoryImageCreateInfoKHR externalMemoryImageCreateInfo = {
+ VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO_KHR
+ };
+#if defined(USE_OZONE)
+ VkSubresourceLayout planeLayout = {};
+ VkImageDrmFormatModifierExplicitCreateInfoEXT modifierInfo = {
+ VK_STRUCTURE_TYPE_IMAGE_DRM_FORMAT_MODIFIER_EXPLICIT_CREATE_INFO_EXT
+ };
+ base::ScopedFD scopedFd;
+
+ if (nativePixmap) {
+ gfx::NativePixmapHandle nativePixmapHandle = nativePixmap->ExportHandle();
+ if (nativePixmapHandle.planes.size() != 1)
+ qFatal("VULKAN: Multiple planes are not supported.");
+
+ planeLayout.offset = nativePixmapHandle.planes[0].offset;
+ planeLayout.size = 0;
+ planeLayout.rowPitch = nativePixmapHandle.planes[0].stride;
+ planeLayout.arrayPitch = 0;
+ planeLayout.depthPitch = 0;
+
+ modifierInfo.drmFormatModifier = nativePixmapHandle.modifier;
+ modifierInfo.drmFormatModifierPlaneCount = 1;
+ modifierInfo.pPlaneLayouts = &planeLayout;
+
+ externalMemoryImageCreateInfo.pNext = &modifierInfo;
+ externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+
+ scopedFd = std::move(nativePixmapHandle.planes[0].fd);
+ } else {
+ externalMemoryImageCreateInfo.pNext = nullptr;
+ externalMemoryImageCreateInfo.handleTypes =
+ VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ VkMemoryGetFdInfoKHR exportInfo = { VK_STRUCTURE_TYPE_MEMORY_GET_FD_INFO_KHR };
+ exportInfo.pNext = nullptr;
+ exportInfo.memory = vkImageInfo.fAlloc.fMemory;
+ exportInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+
+ gpu::VulkanFunctionPointers *vfp = gpu::GetVulkanFunctionPointers();
+ gpu::VulkanDeviceQueue *vulkanDeviceQueue =
+ m_contextState->vk_context_provider()->GetDeviceQueue();
+ VkDevice vulkanDevice = vulkanDeviceQueue->GetVulkanDevice();
+
+ int fd = -1;
+ if (vfp->vkGetMemoryFdKHR(vulkanDevice, &exportInfo, &fd) != VK_SUCCESS)
+ qFatal("VULKAN: Unable to extract file descriptor out of external VkImage.");
+
+ scopedFd.reset(fd);
+ }
+
+ if (!scopedFd.is_valid())
+ qFatal("VULKAN: Unable to extract file descriptor.");
+#elif defined(Q_OS_WIN)
+ externalMemoryImageCreateInfo.pNext = nullptr;
+ externalMemoryImageCreateInfo.handleTypes = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
+
+ HRESULT status = S_OK;
+ HANDLE sharedHandle = nullptr;
+ IDXGIResource1 *resource = nullptr;
+ if (!overlayImage->nv12_texture()) {
+ qWarning("VULKAN: No D3D texture.");
+ return nullptr;
+ }
+ status = overlayImage->nv12_texture()->QueryInterface(__uuidof(IDXGIResource1),
+ (void **)&resource);
+ Q_ASSERT(status == S_OK);
+ status = resource->CreateSharedHandle(NULL, DXGI_SHARED_RESOURCE_READ, NULL, &sharedHandle);
+ Q_ASSERT(status == S_OK);
+
+ if (!sharedHandle)
+ qFatal("VULKAN: Unable to extract shared handle.");
+#endif
+
+ constexpr VkImageUsageFlags kUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
+ | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT
+ | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+
+ VkImageCreateInfo importedImageCreateInfo = { VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO };
+ importedImageCreateInfo.pNext = &externalMemoryImageCreateInfo;
+ importedImageCreateInfo.flags = 0;
+ importedImageCreateInfo.imageType = VK_IMAGE_TYPE_2D;
+ importedImageCreateInfo.format = gpu::ToVkFormat(m_frontBuffer->sharedImageFormat());
+ importedImageCreateInfo.extent.width = static_cast<uint32_t>(size().width());
+ importedImageCreateInfo.extent.height = static_cast<uint32_t>(size().height());
+ importedImageCreateInfo.extent.depth = 1;
+ importedImageCreateInfo.mipLevels = 1;
+ importedImageCreateInfo.arrayLayers = 1;
+ importedImageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT;
+ importedImageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL;
+ importedImageCreateInfo.usage = kUsage;
+ importedImageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+ importedImageCreateInfo.queueFamilyIndexCount = 0;
+ importedImageCreateInfo.pQueueFamilyIndices = nullptr;
+ importedImageCreateInfo.initialLayout = imageLayout;
+
+#if defined(USE_OZONE)
+ if (nativePixmap)
+ importedImageCreateInfo.tiling = VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+ else
+ importedImageCreateInfo.tiling = vkImageInfo.fImageTiling;
+#endif
+
+ VkResult result;
+ VkImage importedImage = VK_NULL_HANDLE;
+ result = df->vkCreateImage(qtVulkanDevice, &importedImageCreateInfo, nullptr /* pAllocator */,
+ &importedImage);
+ if (result != VK_SUCCESS)
+ qFatal() << "VULKAN: vkCreateImage failed result:" << result;
+
+#if defined(USE_OZONE)
+ VkImportMemoryFdInfoKHR importMemoryHandleInfo = {
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_FD_INFO_KHR
+ };
+ importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT_KHR;
+ importMemoryHandleInfo.fd = scopedFd.release();
+
+ if (nativePixmap)
+ importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT;
+#elif defined(Q_OS_WIN)
+ VkImportMemoryWin32HandleInfoKHR importMemoryHandleInfo = {
+ VK_STRUCTURE_TYPE_IMPORT_MEMORY_WIN32_HANDLE_INFO_KHR
+ };
+ importMemoryHandleInfo.pNext = nullptr;
+ importMemoryHandleInfo.handleType = VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
+ importMemoryHandleInfo.handle = sharedHandle;
+#endif
+
+ VkMemoryDedicatedAllocateInfoKHR dedicatedMemoryInfo = {
+ VK_STRUCTURE_TYPE_MEMORY_DEDICATED_ALLOCATE_INFO_KHR
+ };
+ dedicatedMemoryInfo.pNext = &importMemoryHandleInfo;
+ dedicatedMemoryInfo.image = importedImage;
+
+ VkMemoryAllocateInfo memoryAllocateInfo = { VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO };
+ memoryAllocateInfo.pNext = &dedicatedMemoryInfo;
+
+ VkMemoryRequirements requirements;
+ df->vkGetImageMemoryRequirements(qtVulkanDevice, importedImage, &requirements);
+ if (!requirements.memoryTypeBits)
+ qFatal("VULKAN: vkGetImageMemoryRequirements failed.");
+
+ VkPhysicalDeviceMemoryProperties memoryProperties;
+ f->vkGetPhysicalDeviceMemoryProperties(qtPhysicalDevice, &memoryProperties);
+ constexpr VkMemoryPropertyFlags flags = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
+ constexpr uint32_t kMaxIndex = 31;
+ uint32_t memoryTypeIndex = kMaxIndex + 1;
+ for (uint32_t i = 0; i <= kMaxIndex; i++) {
+ if (((1u << i) & requirements.memoryTypeBits) == 0)
+ continue;
+ if ((memoryProperties.memoryTypes[i].propertyFlags & flags) != flags)
+ continue;
+ memoryTypeIndex = i;
+ break;
+ }
+
+ if (memoryTypeIndex > kMaxIndex)
+ qFatal("VULKAN: Cannot find valid memory type index.");
+
+ memoryAllocateInfo.allocationSize = requirements.size;
+ memoryAllocateInfo.memoryTypeIndex = memoryTypeIndex;
+
+ VkDeviceMemory importedImageMemory = VK_NULL_HANDLE;
+ result = df->vkAllocateMemory(qtVulkanDevice, &memoryAllocateInfo, nullptr /* pAllocator */,
+ &importedImageMemory);
+ if (result != VK_SUCCESS)
+ qFatal() << "VULKAN: vkAllocateMemory failed result:" << result;
+
+ df->vkBindImageMemory(qtVulkanDevice, importedImage, importedImageMemory, 0);
+
+ QQuickWindow::CreateTextureOptions texOpts(textureOptions);
+ QSGTexture *texture = QNativeInterface::QSGVulkanTexture::fromNative(importedImage, imageLayout,
+ win, size(), texOpts);
+
+ m_frontBuffer->textureCleanupCallback = [=]() {
+ df->vkDestroyImage(qtVulkanDevice, importedImage, nullptr);
+ df->vkFreeMemory(qtVulkanDevice, importedImageMemory, nullptr);
+#if defined(Q_OS_WIN)
+ ::CloseHandle(sharedHandle);
+#endif
+ };
+
+ return texture;
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/compositor/native_skia_output_device_vulkan.h b/src/core/compositor/native_skia_output_device_vulkan.h
new file mode 100644
index 000000000..bead0cc11
--- /dev/null
+++ b/src/core/compositor/native_skia_output_device_vulkan.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2024 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NATIVE_SKIA_OUTPUT_DEVICE_VULKAN_H
+#define NATIVE_SKIA_OUTPUT_DEVICE_VULKAN_H
+
+#include "native_skia_output_device.h"
+
+namespace QtWebEngineCore {
+
+class NativeSkiaOutputDeviceVulkan final : public NativeSkiaOutputDevice
+{
+public:
+ NativeSkiaOutputDeviceVulkan(
+ scoped_refptr<gpu::SharedContextState> contextState, bool requiresAlpha,
+ gpu::MemoryTracker *memoryTracker, viz::SkiaOutputSurfaceDependency *dependency,
+ gpu::SharedImageFactory *shared_image_factory,
+ gpu::SharedImageRepresentationFactory *shared_image_representation_factory,
+ DidSwapBufferCompleteCallback didSwapBufferCompleteCallback);
+ ~NativeSkiaOutputDeviceVulkan() override;
+
+ // Overridden from Compositor:
+ QSGTexture *texture(QQuickWindow *win, uint32_t textureOptions) override;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // NATIVE_SKIA_OUTPUT_DEVICE_VULKAN_H
diff --git a/src/core/compositor/vulkan_implementation_qt.cpp b/src/core/compositor/vulkan_implementation_qt.cpp
index f24ec334b..2f2259666 100644
--- a/src/core/compositor/vulkan_implementation_qt.cpp
+++ b/src/core/compositor/vulkan_implementation_qt.cpp
@@ -10,6 +10,8 @@
#include "gpu/vulkan/vulkan_util.h"
#include "ui/gfx/gpu_fence.h"
+#include <vulkan/vulkan.h>
+
namespace gpu {
VulkanImplementationQt::VulkanImplementationQt() : VulkanImplementation(false) { }
@@ -25,12 +27,13 @@ bool VulkanImplementationQt::InitializeVulkanInstance(bool /*using_surface*/)
auto env = base::Environment::Create();
std::string vulkan_path;
- if (!env->GetVar("QT_VULKAN_LIB", &vulkan_path))
-#ifdef Q_OS_WIN
+ if (!env->GetVar("QT_VULKAN_LIB", &vulkan_path)) {
+#if BUILDFLAG(IS_WIN)
vulkan_path = "vulkan-1.dll";
#else
vulkan_path = "libvulkan.so.1";
#endif
+ }
if (!vulkan_instance_.Initialize(base::FilePath::FromUTF8Unsafe(vulkan_path),
required_extensions, {})) {
@@ -66,7 +69,7 @@ std::vector<const char *> VulkanImplementationQt::GetRequiredDeviceExtensions()
{
return {
VK_KHR_EXTERNAL_MEMORY_EXTENSION_NAME,
-#ifdef Q_OS_WIN
+#if BUILDFLAG(IS_WIN)
VK_KHR_EXTERNAL_MEMORY_WIN32_EXTENSION_NAME,
#else
VK_KHR_EXTERNAL_MEMORY_FD_EXTENSION_NAME,
@@ -78,10 +81,13 @@ std::vector<const char *> VulkanImplementationQt::GetOptionalDeviceExtensions()
{
return {
VK_KHR_EXTERNAL_SEMAPHORE_EXTENSION_NAME,
-#ifdef Q_OS_WIN
+#if BUILDFLAG(IS_WIN)
VK_KHR_EXTERNAL_SEMAPHORE_WIN32_EXTENSION_NAME,
#else
VK_KHR_EXTERNAL_SEMAPHORE_FD_EXTENSION_NAME,
+ VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME,
+ VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME,
+ VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME,
#endif
};
}
@@ -99,55 +105,58 @@ VulkanImplementationQt::ExportVkFenceToGpuFence(VkDevice /*vk_device*/, VkFence
return nullptr;
}
-VkSemaphore VulkanImplementationQt::CreateExternalSemaphore(VkDevice vk_device)
-{
- return CreateExternalVkSemaphore(
-#ifdef Q_OS_WIN
- vk_device, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT);
-#else
- vk_device, VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
-#endif
-}
-
VkSemaphore VulkanImplementationQt::ImportSemaphoreHandle(VkDevice vk_device,
SemaphoreHandle sync_handle)
{
return ImportVkSemaphoreHandle(vk_device, std::move(sync_handle));
}
-SemaphoreHandle VulkanImplementationQt::GetSemaphoreHandle(VkDevice vk_device,
- VkSemaphore vk_semaphore)
+VkExternalSemaphoreHandleTypeFlagBits VulkanImplementationQt::GetExternalSemaphoreHandleType()
{
- return GetVkSemaphoreHandle(vk_device, vk_semaphore,
-#ifdef Q_OS_WIN
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT);
+#if BUILDFLAG(IS_WIN)
+ return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_WIN32_BIT;
#else
- VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT);
-#endif
-}
-
-VkExternalMemoryHandleTypeFlagBits VulkanImplementationQt::GetExternalImageHandleType()
-{
-#ifdef Q_OS_WIN
- return VK_EXTERNAL_MEMORY_HANDLE_TYPE_D3D11_TEXTURE_BIT;
-#else
- return VK_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD_BIT;
+ return VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
#endif
}
bool VulkanImplementationQt::CanImportGpuMemoryBuffer(
- VulkanDeviceQueue* /*device_queue*/,
- gfx::GpuMemoryBufferType /*memory_buffer_type*/)
+ VulkanDeviceQueue *device_queue,
+ gfx::GpuMemoryBufferType memory_buffer_type)
{
+#if BUILDFLAG(IS_LINUX)
+ const auto &enabled_extensions = device_queue->enabled_extensions();
+ return gfx::HasExtension(enabled_extensions,
+ VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME) &&
+ gfx::HasExtension(enabled_extensions,
+ VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME) &&
+ memory_buffer_type == gfx::GpuMemoryBufferType::NATIVE_PIXMAP;
+#else
return false;
+#endif
}
-std::unique_ptr<VulkanImage> VulkanImplementationQt::CreateImageFromGpuMemoryHandle(VulkanDeviceQueue *, gfx::GpuMemoryBufferHandle,
- gfx::Size, VkFormat,
+std::unique_ptr<VulkanImage> VulkanImplementationQt::CreateImageFromGpuMemoryHandle(VulkanDeviceQueue *device_queue,
+ gfx::GpuMemoryBufferHandle gmb_handle,
+ gfx::Size size,
+ VkFormat vk_format,
const gfx::ColorSpace &)
{
- NOTREACHED();
+#if BUILDFLAG(IS_LINUX)
+ constexpr auto kUsage =
+ VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT |
+ VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
+ auto tiling = gmb_handle.native_pixmap_handle.modifier ==
+ gfx::NativePixmapHandle::kNoModifier
+ ? VK_IMAGE_TILING_OPTIMAL
+ : VK_IMAGE_TILING_DRM_FORMAT_MODIFIER_EXT;
+ return gpu::VulkanImage::CreateFromGpuMemoryBufferHandle(
+ device_queue, std::move(gmb_handle), size, vk_format, kUsage, /*flags=*/0,
+ tiling, VK_QUEUE_FAMILY_EXTERNAL);
+#else
+ NOTIMPLEMENTED();
return nullptr;
+#endif
}
} // namespace gpu
diff --git a/src/core/compositor/vulkan_implementation_qt.h b/src/core/compositor/vulkan_implementation_qt.h
index 56a61e086..88983331f 100644
--- a/src/core/compositor/vulkan_implementation_qt.h
+++ b/src/core/compositor/vulkan_implementation_qt.h
@@ -28,10 +28,8 @@ public:
VkFence CreateVkFenceForGpuFence(VkDevice vk_device) override;
std::unique_ptr<gfx::GpuFence> ExportVkFenceToGpuFence(VkDevice vk_device,
VkFence vk_fence) override;
- VkSemaphore CreateExternalSemaphore(VkDevice vk_device) override;
VkSemaphore ImportSemaphoreHandle(VkDevice vk_device, SemaphoreHandle handle) override;
- SemaphoreHandle GetSemaphoreHandle(VkDevice vk_device, VkSemaphore vk_semaphore) override;
- VkExternalMemoryHandleTypeFlagBits GetExternalImageHandleType() override;
+ VkExternalSemaphoreHandleTypeFlagBits GetExternalSemaphoreHandleType() override;
bool CanImportGpuMemoryBuffer(VulkanDeviceQueue* device_queue,
gfx::GpuMemoryBufferType memory_buffer_type) override;
std::unique_ptr<VulkanImage> CreateImageFromGpuMemoryHandle(VulkanDeviceQueue *device_queue,
diff --git a/src/core/configure.json b/src/core/configure.json
deleted file mode 100644
index e73f471cf..000000000
--- a/src/core/configure.json
+++ /dev/null
@@ -1,288 +0,0 @@
-{
- "module": "webenginecore",
- "depends": [
- "buildtools-private",
- "core-private",
- "gui-private",
- "printsupport"
- ],
- "condition": "module.gui && features.build-qtwebengine-core && features.webengine-core-support",
- "testDir": "../../config.tests",
- "commandline": {
- "options": {
- "webengine-alsa": "boolean",
- "webengine-embedded-build": "boolean",
- "webengine-full-debug-info": "boolean",
- "webengine-icu": { "type": "enum", "name": "webengine-system-icu", "values": { "system": "yes", "qt": "no" } },
- "webengine-ffmpeg": { "type": "enum", "name": "webengine-system-ffmpeg", "values": { "system": "yes", "qt": "no" } },
- "webengine-opus": { "type": "enum", "name": "webengine-system-opus", "values": { "system": "yes", "qt": "no" } },
- "webengine-webp": { "type": "enum", "name": "webengine-system-libwebp", "values": { "system": "yes", "qt": "no" } },
- "webengine-pepper-plugins": "boolean",
- "webengine-printing-and-pdf": "boolean",
- "webengine-proprietary-codecs": "boolean",
- "webengine-pulseaudio": "boolean",
- "webengine-spellchecker": "boolean",
- "webengine-native-spellchecker": "boolean",
- "webengine-extensions": "boolean",
- "webengine-webrtc": "boolean",
- "webengine-webrtc-pipewire": "boolean",
- "webengine-geolocation": "boolean",
- "webengine-webchannel": "boolean",
- "webengine-kerberos": "boolean",
- "alsa": { "type": "boolean", "name": "webengine-alsa" },
- "pulseaudio": { "type": "boolean", "name": "webengine-pulseaudio" },
- "ffmpeg": { "type": "enum", "name": "webengine-system-ffmpeg", "values": { "system": "yes", "qt": "no" } },
- "opus": { "type": "enum", "name": "webengine-system-opus", "values": { "system": "yes", "qt": "no" } },
- "webp": { "type": "enum", "name": "webengine-system-libwebp", "values": { "system": "yes", "qt": "no" } },
- "pepper-plugins": { "type": "boolean", "name": "webengine-pepper-plugins" },
- "printing-and-pdf": { "type": "boolean", "name": "webengine-printing-and-pdf" },
- "proprietary-codecs": { "type": "boolean", "name": "webengine-proprietary-codecs" },
- "spellchecker": { "type": "boolean", "name": "webengine-spellchecker" },
- "extensions": { "type": "boolean", "name": "webengine-extensions" },
- "webrtc": { "type": "boolean", "name": "webengine-webrtc" }
- }
- },
-
- "libraries": {
- "webengine-alsa": {
- "label": "alsa",
- "test": {
- "tail": [
- "#if SND_LIB_VERSION < 0x1000a // 1.0.10",
- "#error Alsa version found too old, require >= 1.0.10",
- "#endif"
- ]
- },
- "headers" : ["alsa/asoundlib.h"],
- "sources" : [{ "type": "pkgConfig", "args": "alsa" }
- ]
- },
- "webengine-poppler-cpp": {
- "label": "poppler-cpp",
- "sources": [
- { "type": "pkgConfig", "args": "poppler-cpp" }
- ]
- },
- "webengine-pulseaudio": {
- "label": "pulseaudio >= 0.9.10",
- "sources": [
- { "type": "pkgConfig", "args": "libpulse >= 0.9.10 libpulse-mainloop-glib" }
- ]
- },
- "webengine-gio": {
- "label": "gio",
- "sources": [
- { "type": "pkgConfig", "args": "gio-2.0" }
- ]
- }
- },
- "tests" : {
- "webengine-host-compiler": {
- "label": "host compiler",
- "test": "hostcompiler",
- "host": "true",
- "type": "compile"
- },
- "webengine-host-pkg-config": {
- "label": "host pkg-config",
- "type": "detectHostPkgConfig",
- "log": "path"
- },
- "webengine-embedded-build": {
- "label": "embedded build",
- "type": "detectEmbedded"
- }
- },
- "features": {
- "webengine-embedded-build": {
- "label": "Embedded build",
- "purpose": "Enables the embedded build configuration.",
- "condition": "config.unix",
- "autoDetect": "tests.webengine-embedded-build",
- "output": [ "privateFeature" ]
- },
- "webengine-alsa": {
- "label": "Use ALSA",
- "condition": "config.unix && libs.webengine-alsa",
- "output": [ "privateFeature" ]
- },
- "webengine-geolocation": {
- "label": "Geolocation",
- "condition": "module.positioning",
- "output": [ "publicFeature" ]
- },
- "webengine-pulseaudio": {
- "label": "Use PulseAudio",
- "autoDetect": "config.unix",
- "condition": "libs.webengine-pulseaudio",
- "output": [ "privateFeature" ]
- },
- "webengine-pepper-plugins": {
- "label": "Pepper Plugins",
- "purpose": "Enables use of Pepper Flash plugins.",
- "autoDetect": "!features.webengine-embedded-build",
- "output": [ "privateFeature" ]
- },
- "webengine-printing-and-pdf": {
- "label": "Printing and PDF",
- "purpose": "Provides printing and output to PDF.",
- "condition": "module.printsupport && features.printer",
- "autoDetect": "!features.webengine-embedded-build",
- "output": [ "privateFeature" ]
- },
- "webengine-webchannel": {
- "label": "WebChannel support",
- "purpose": "Provides QtWebChannel integration.",
- "section": "WebEngine",
- "condition": "module.webchannel",
- "output": [ "publicFeature" ]
- },
- "webengine-proprietary-codecs": {
- "label": "Proprietary Codecs",
- "purpose": "Enables the use of proprietary codecs such as h.264/h.265 and MP3.",
- "autoDetect": false,
- "output": [ "privateFeature" ]
- },
- "webengine-kerberos": {
- "label": "Kerberos Authentication",
- "purpose": "Enables Kerberos Authentication Support",
- "autoDetect": "config.win32",
- "section": "WebEngine",
- "output": [ "privateFeature" ]
- },
- "webengine-spellchecker": {
- "label": "Spellchecker",
- "purpose": "Provides a spellchecker.",
- "output": [ "publicFeature" ]
- },
- "webengine-native-spellchecker": {
- "label": "Native Spellchecker",
- "purpose": "Use the system's native spellchecking engine.",
- "autoDetect": false,
- "condition": "config.macos && features.webengine-spellchecker",
- "output": [ "publicFeature" ]
- },
- "webengine-extensions": {
- "label": "Extensions",
- "purpose": "Enables Chromium extensions within certain limits. Currently used for enabling the pdf viewer.",
- "section": "WebEngine",
- "condition": "features.webengine-printing-and-pdf",
- "autoDetect": "features.webengine-printing-and-pdf",
- "output": [ "publicFeature" ]
- },
- "webengine-webrtc": {
- "label": "WebRTC",
- "purpose": "Provides WebRTC support.",
- "autoDetect": "!features.webengine-embedded-build",
- "output": [ "privateFeature" ]
- },
- "webengine-webrtc-pipewire": {
- "label": "PipeWire over GIO",
- "purpose": "Provides PipeWire support in WebRTC using GIO.",
- "condition": "features.webengine-webrtc && libs.webengine-gio",
- "autoDetect": "false",
- "output": [ "privateFeature" ]
- },
- "webengine-ozone" : {
- "label": "Support qpa-xcb",
- "condition": "features.webengine-ozone-x11",
- "output": [ "privateFeature" ]
- },
- "webengine-poppler-cpp": {
- "label": "poppler-cpp",
- "autoDetect": "config.unix",
- "condition": "libs.webengine-poppler-cpp",
- "output": [ "privateFeature" ]
- },
- "webengine-full-debug-info": {
- "label": "Full debug information",
- "purpose": "Enables debug information for Blink and V8.",
- "autoDetect": false,
- "condition": "config.debug || features.debug_and_release || features.force_debug_info",
- "output": [
- { "type": "privateConfig", "name": "v8base_debug" },
- { "type": "privateConfig", "name": "webcore_debug" }
- ]
- }
- },
-
- "report": [
- {
- "type": "warning",
- "condition": "config.unix && !features.webengine-host-pkg-config",
- "message": "host pkg-config not found"
- },
- {
- "type": "warning",
- "condition": "config.linux && features.webengine-embedded-build && !features.webengine-system-ffmpeg && arch.arm && !features.webengine-arm-thumb",
- "message": "Thumb instruction set is required to build ffmpeg for QtWebEngine."
- }
- ],
-
- "summary": [
- {
- "section": "Qt WebEngineCore",
- "condition": "features.build-qtwebengine-core",
- "entries": [
- "webengine-embedded-build",
- "webengine-full-debug-info",
- "webengine-pepper-plugins",
- "webengine-printing-and-pdf",
- "webengine-proprietary-codecs",
- "webengine-spellchecker",
- "webengine-native-spellchecker",
- "webengine-webrtc",
- "webengine-webrtc-pipewire",
- "webengine-geolocation",
- "webengine-webchannel",
- "webengine-kerberos",
- "webengine-extensions",
- {
- "type": "feature",
- "args": "webengine-ozone",
- "condition": "config.unix"
- },
- {
- "type": "feature",
- "args": "webengine-alsa",
- "condition": "config.unix"
- },
- {
- "type": "feature",
- "args": "webengine-pulseaudio",
- "condition": "config.unix"
- },
- {
- "message": "macOS version",
- "type": "macosToolchainVersion",
- "args": "macosVersion",
- "condition": "config.macos"
- },
- {
- "message": "Xcode version",
- "type": "macosToolchainVersion",
- "args": "xcodeVersion",
- "condition": "config.macos"
- },
- {
- "message": "Clang version",
- "type": "macosToolchainVersion",
- "args": "clangVersion",
- "condition": "config.macos"
- },
- {
- "message": "macOS SDK version",
- "type": "macosToolchainVersion",
- "args": "sdkVersion",
- "condition": "config.macos"
- },
- {
- "message": "macOS minimum deployment target",
- "type": "macosToolchainVersion",
- "args": "deploymentTarget",
- "condition": "config.macos"
- }
- ]
- }
- ]
-}
diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in
index d38e84973..986db5026 100644
--- a/src/core/configure/BUILD.root.gn.in
+++ b/src/core/configure/BUILD.root.gn.in
@@ -11,6 +11,7 @@ import("//build/config/locales.gni")
import("//chrome/chrome_repack_locales.gni")
import("//extensions/buildflags/buildflags.gni")
import("//ui/ozone/ozone.gni")
+import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
# Workaround for cmake configure_file command. Words wrapped with @ characters are
# handled as variables in this file.
@@ -80,26 +81,26 @@ config("QtWebEngineCore_config") {
declare_args() {
use_embedded_config = false
+ enable_webenginedriver = true
}
config("embedded_config") {
defines = [ "QTWEBENGINE_EMBEDDED_SWITCHES=1" ]
}
-config("cpp17_config") {
- # static initialized constexpr expressions must be compiled always as c++14 or always as c++17
- # and our qtwebengine core sources use them as c++17
+config("cpp20_config") {
+ # Chromium is built with C++20
if (is_win) {
- cflags_cc = [ "/std:c++17" ]
+ cflags_cc = [ "/std:c++20" ]
} else {
- cflags_cc = [ "-std=c++17" ]
+ cflags_cc = [ "-std=c++20" ]
}
}
shared_library("QtWebEngineCore") {
- rsp_types = [ "objects", "archives", "libs" ]
+ rsp_types = [ "objects", "archives", "libs", "ldir"]
configs += [
- ":cpp17_config",
+ ":cpp20_config",
":QtWebEngineCore_config",
"//build/config:precompiled_headers"
]
@@ -109,7 +110,8 @@ shared_library("QtWebEngineCore") {
"//third_party/boringssl/src/include",
"//third_party/skia/include/core"
]
- defines = [ "CHROMIUM_VERSION=\"" + chromium_version[0] + "\"" ]
+ data_deps = []
+ defines = [ "CHROMIUM_VERSION=" + chromium_version[0] ]
deps = [
"//base",
"//components/autofill/content/browser",
@@ -117,11 +119,13 @@ shared_library("QtWebEngineCore") {
"//components/autofill/core/browser",
"//components/autofill/core/browser:buildflags",
"//components/cdm/renderer",
+ "//components/embedder_support/origin_trials",
"//components/error_page/common",
"//components/favicon/content",
"//components/gcm_driver",
"//components/history/content/browser",
"//components/keyed_service/content",
+ "//components/lens:buildflags",
"//components/navigation_interception",
"//components/network_hints/browser",
"//components/network_hints/common:mojo_bindings",
@@ -132,6 +136,7 @@ shared_library("QtWebEngineCore") {
"//components/web_cache/browser",
"//components/web_cache/renderer",
"//components/spellcheck:buildflags",
+ "//components/supervised_user/core/common:buildflags",
"//components/profile_metrics",
"//components/proxy_config",
"//components/user_prefs",
@@ -164,12 +169,16 @@ shared_library("QtWebEngineCore") {
if (is_win) {
configs += [ "//build/config/compiler:rtti" ]
- data_deps = [ ":QtWebEngineCoreSandbox" ]
+ data_deps += [ ":QtWebEngineCoreSandbox" ]
}
if (use_embedded_config) {
configs += [ ":embedded_config" ]
}
+ if (is_apple) {
+ configs -= [ "//build/config/compiler:enable_arc" ]
+ }
+
sources = [
@GN_HEADERS@,
@GN_SOURCES@
@@ -185,6 +194,11 @@ shared_library("QtWebEngineCore") {
":generate_cpp_mocs",
]
}
+ if (use_v8_context_snapshot) {
+ data_deps += [
+ "//tools/v8_context_snapshot:v8_context_snapshot"
+ ]
+ }
}
source_set("qtwebengine_spellcheck_sources") {
@@ -216,16 +230,44 @@ source_set("qtwebengine_spellcheck_sources") {
}
}
+source_set("devtools_sources") {
+ configs += [ ":cpp20_config" ]
+ deps = [
+ "//components/zoom",
+ "//third_party/blink/public/mojom:mojom_platform",
+ ]
+ sources = [
+ "//chrome/browser/devtools/devtools_eye_dropper.cc",
+ "//chrome/browser/devtools/devtools_eye_dropper.h",
+ "//chrome/browser/devtools/devtools_file_helper.cc",
+ "//chrome/browser/devtools/devtools_file_helper.h",
+ "//chrome/browser/devtools/devtools_file_system_indexer.cc",
+ "//chrome/browser/devtools/devtools_file_system_indexer.h",
+ "//chrome/browser/devtools/devtools_file_watcher.cc",
+ "//chrome/browser/devtools/devtools_file_watcher.h",
+ "//chrome/browser/devtools/url_constants.cc",
+ "//chrome/browser/devtools/url_constants.h",
+ "//chrome/browser/devtools/devtools_ui_bindings.cc",
+ "//chrome/browser/devtools/devtools_ui_bindings.h",
+ "//chrome/browser/devtools/devtools_settings.cc",
+ "//chrome/browser/devtools/devtools_settings.h",
+ "//chrome/browser/devtools/devtools_embedder_message_dispatcher.cc",
+ "//chrome/browser/devtools/devtools_embedder_message_dispatcher.h",
+ ]
+}
+
source_set("qtwebengine_sources") {
configs += [
- ":cpp17_config",
+ ":cpp20_config",
"//skia:skia_config",
"//third_party/boringssl:external_config",
]
deps = [
+ ":devtools_sources",
"//build:branding_buildflags",
"//build/config/chromebox_for_meetings:buildflags",
"//chrome/browser:dev_ui_browser_resources_grit",
+ "//chrome/browser/resources/accessibility:resources",
"//chrome/browser/resources/net_internals:resources",
"//chrome/browser/signin:identity_manager_provider",
"//chrome/common:buildflags",
@@ -234,6 +276,7 @@ source_set("qtwebengine_sources") {
"//components/embedder_support:embedder_support",
"//components/nacl/common:buildflags",
"//components/performance_manager",
+ "//components/permissions:permissions_common",
"//components/plugins/renderer/",
"//content/browser/resources/quota:resources",
"//extensions/buildflags:buildflags",
@@ -246,19 +289,22 @@ source_set("qtwebengine_sources") {
sources = [
"//chrome/browser/accessibility/accessibility_ui.cc",
"//chrome/browser/accessibility/accessibility_ui.h",
- "//chrome/browser/devtools/devtools_eye_dropper.cc",
- "//chrome/browser/devtools/devtools_eye_dropper.h",
- "//chrome/browser/devtools/devtools_file_helper.cc",
- "//chrome/browser/devtools/devtools_file_helper.h",
- "//chrome/browser/devtools/devtools_file_watcher.cc",
- "//chrome/browser/devtools/devtools_file_watcher.h",
"//chrome/browser/gcm/gcm_product_util.cc",
"//chrome/browser/gcm/gcm_product_util.h",
"//chrome/browser/gcm/gcm_profile_service_factory.cc",
"//chrome/browser/gcm/gcm_profile_service_factory.h",
"//chrome/browser/gcm/instance_id/instance_id_profile_service_factory.cc",
"//chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h",
+ "//chrome/browser/media/webrtc/desktop_capturer_wrapper.cc",
+ "//chrome/browser/media/webrtc/desktop_capturer_wrapper.h",
+ "//chrome/browser/media/webrtc/desktop_media_list.cc",
"//chrome/browser/media/webrtc/desktop_media_list.h",
+ "//chrome/browser/media/webrtc/desktop_media_list_base.cc",
+ "//chrome/browser/media/webrtc/desktop_media_list_base.h",
+ "//chrome/browser/media/webrtc/native_desktop_media_list.cc",
+ "//chrome/browser/media/webrtc/native_desktop_media_list.h",
+ "//chrome/browser/media/webrtc/thumbnail_capturer.cc",
+ "//chrome/browser/media/webrtc/thumbnail_capturer.h",
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.cc",
"//chrome/browser/net/chrome_mojo_proxy_resolver_factory.h",
"//chrome/browser/prefs/chrome_command_line_pref_store.cc",
@@ -317,7 +363,6 @@ source_set("qtwebengine_sources") {
"//chrome/browser/ui/webui/webui_util.h",
"//chrome/common/chrome_switches.cc",
"//chrome/common/chrome_switches.h",
- "//chrome/common/pref_names.cc",
"//chrome/common/pref_names.h",
"//chrome/common/url_constants.cc",
"//chrome/common/url_constants.h",
@@ -326,6 +371,28 @@ source_set("qtwebengine_sources") {
"//components/embedder_support/user_agent_utils.cc",
"//components/embedder_support/user_agent_utils.h",
]
+ if (use_ozone) {
+ deps += [
+ "//ui/gfx/linux:drm",
+ ]
+
+ sources += [
+ "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.cc",
+ "//ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h",
+ ]
+
+ if (ozone_platform_x11) {
+ deps += [
+ "//ui/base/x:gl",
+ "//ui/gfx/linux:gpu_memory_buffer_support_x11",
+ ]
+
+ sources += [
+ "//ui/ozone/platform/x11/gl_egl_utility_x11.cc",
+ "//ui/ozone/platform/x11/gl_egl_utility_x11.h",
+ ]
+ }
+ }
if (enable_extensions) {
deps += [
":qtwebengine_extensions_features",
@@ -343,7 +410,6 @@ source_set("qtwebengine_sources") {
"//extensions/common:core_api_provider",
"//extensions/browser",
"//extensions/browser/api",
- "//extensions/browser:core_api_provider",
"//extensions/renderer",
"//extensions:extensions_resources",
"//extensions/strings",
@@ -373,6 +439,9 @@ source_set("qtwebengine_sources") {
"//chrome/browser/ui/webui/sandbox/sandbox_internals_ui.cc",
"//chrome/browser/ui/webui/sandbox/sandbox_internals_ui.h",
]
+ deps += [
+ "//chrome/browser/resources/sandbox_internals:resources",
+ ]
}
if (is_win) {
sources += [
@@ -471,7 +540,7 @@ source_set("qtwebengine_sources") {
if (is_win) {
static_library("QtWebEngineCoreSandbox") {
complete_static_lib = true
- configs += [ ":cpp17_config",
+ configs += [ ":cpp20_config",
":QtWebEngineCore_config",
"//build/config:precompiled_headers"
]
@@ -501,40 +570,52 @@ group("qtwebengine_resources") {
repack("qtwebengine_repack_resources") {
sources = [
"$root_gen_dir/qtwebengine/qt_webengine_resources.pak",
+ "$root_gen_dir/chrome/accessibility_resources.pak",
"$root_gen_dir/chrome/common_resources.pak",
"$root_gen_dir/chrome/dev_ui_browser_resources.pak",
"$root_gen_dir/chrome/net_internals_resources.pak",
"$root_gen_dir/components/components_resources.pak",
"$root_gen_dir/components/dev_ui_components_resources.pak",
+ "$root_gen_dir/content/attribution_internals_resources.pak",
"$root_gen_dir/content/browser/resources/media/media_internals_resources.pak",
"$root_gen_dir/content/browser/tracing/tracing_resources.pak",
"$root_gen_dir/content/content_resources.pak",
- "$root_gen_dir/content/dev_ui_content_resources.pak",
+ "$root_gen_dir/content/gpu_resources.pak",
+ "$root_gen_dir/content/histograms_resources.pak",
"$root_gen_dir/content/indexed_db_resources.pak",
+ "$root_gen_dir/content/network_errors_resources.pak",
+ "$root_gen_dir/content/process_resources.pak",
"$root_gen_dir/content/quota_internals_resources.pak",
+ "$root_gen_dir/content/service_worker_resources.pak",
"$root_gen_dir/mojo/public/js/mojo_bindings_resources.pak",
"$root_gen_dir/net/net_resources.pak",
"$root_gen_dir/third_party/blink/public/resources/blink_resources.pak",
- "$root_gen_dir/ui/resources/webui_generated_resources.pak",
+ "$root_gen_dir/ui/resources/webui_resources.pak",
]
output = "$root_out_dir/qtwebengine_resources.pak"
deps = [
"//qtwebengine/browser:qt_webengine_resources",
"//chrome/browser:dev_ui_browser_resources_grit",
+ "//chrome/browser/resources/accessibility:resources",
"//chrome/browser/resources/net_internals:resources",
"//chrome/common:resources_grit",
"//components/resources:components_resources_grit",
"//components/resources:dev_ui_components_resources_grit",
+ "//content/browser/resources/attribution_reporting:resources",
+ "//content/browser/resources/gpu:resources",
+ "//content/browser/resources/histograms:resources_grit",
+ "//content/browser/resources/indexed_db:resources",
"//content/browser/resources/media:resources",
+ "//content/browser/resources/net:resources",
+ "//content/browser/resources/process:resources",
+ "//content/browser/resources/quota:resources",
+ "//content/browser/resources/service_worker:resources",
"//content/browser/tracing:resources",
"//content:content_resources",
- "//content/browser/resources/indexed_db:resources",
- "//content/browser/resources/quota:resources",
- "//content:dev_ui_content_resources_grit",
"//mojo/public/js:resources",
"//net:net_resources_grit",
"//third_party/blink/public:resources_grit",
- "//ui/resources:webui_generated_resources_grd",
+ "//ui/resources:webui_resources_grd",
]
if (enable_extensions) {
sources += [
@@ -572,6 +653,14 @@ repack("qtwebengine_repack_resources") {
"//chrome/browser/resources/pdf:resources",
]
}
+ if (is_linux || is_win) {
+ sources += [
+ "$root_gen_dir/chrome/sandbox_internals_resources.pak",
+ ]
+ deps += [
+ "//chrome/browser/resources/sandbox_internals:resources_grit",
+ ]
+ }
}
repack("qtwebengine_repack_resources_100") {
@@ -669,7 +758,7 @@ if (enable_extensions) {
if (enable_spellcheck) {
shared_library("convert_dict") {
- rsp_types = [ "objects", "archives", "libs" ]
+ rsp_types = [ "objects", "archives", "libs", "ldir" ]
configs += [ "//build/config/compiler:wexit_time_destructors" ]
deps = [
"//chrome/tools/convert_dict:lib",
@@ -679,3 +768,12 @@ if (enable_spellcheck) {
]
}
}
+
+if (enable_webenginedriver) {
+ group("webenginedriver_group") {
+ testonly = true
+ deps = [
+ "//chrome/test/chromedriver:chromedriver_server",
+ ]
+ }
+}
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 553228ffc..53c2caa2d 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -70,7 +70,6 @@
#include "net/proxying_restricted_cookie_manager_qt.h"
#include "net/proxying_url_loader_factory_qt.h"
#include "net/system_network_context_manager.h"
-#include "ozone/gl_share_context_qt.h"
#include "platform_notification_service_qt.h"
#include "profile_qt.h"
#include "profile_io_data_qt.h"
@@ -84,15 +83,11 @@
#include "web_engine_context.h"
#include "web_engine_library_info.h"
#include "web_engine_settings.h"
+#include "authenticator_request_client_delegate_qt.h"
#include "api/qwebenginecookiestore.h"
#include "api/qwebenginecookiestore_p.h"
#include "api/qwebengineurlrequestinfo_p.h"
-#if QT_CONFIG(opengl)
-#include <QOpenGLContext>
-#include <QOpenGLExtraFunctions>
-#endif
-
#if QT_CONFIG(webengine_geolocation)
#include "base/memory/ptr_util.h"
#include "location_provider_qt.h"
@@ -151,7 +146,9 @@
#if BUILDFLAG(ENABLE_PDF)
#include "components/pdf/browser/pdf_navigation_throttle.h"
#include "components/pdf/browser/pdf_url_loader_request_interceptor.h"
-#include "components/pdf/browser/pdf_web_contents_helper.h"
+#include "components/pdf/browser/pdf_document_helper.h"
+
+#include "printing/pdf_document_helper_client_qt.h"
#endif
#if BUILDFLAG(ENABLE_PDF) && BUILDFLAG(ENABLE_EXTENSIONS)
@@ -160,11 +157,6 @@
#include <QGuiApplication>
#include <QStandardPaths>
-#include <qpa/qplatformnativeinterface.h>
-
-QT_BEGIN_NAMESPACE
-Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context();
-QT_END_NAMESPACE
// Implement IsHandledProtocol as declared in //url/url_util_qt.h.
namespace url {
@@ -260,13 +252,6 @@ void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost
renderer_configuration->SetInitialConfiguration(is_incognito_process);
}
-gl::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup()
-{
- if (!m_shareGroupQt.get())
- m_shareGroupQt = new ShareGroupQt;
- return m_shareGroupQt.get();
-}
-
content::MediaObserver *ContentBrowserClientQt::GetMediaObserver()
{
return MediaCaptureDevicesDispatcher::GetInstance();
@@ -303,13 +288,15 @@ void ContentBrowserClientQt::AllowCertificateError(content::WebContents *webCont
}
-base::OnceClosure ContentBrowserClientQt::SelectClientCertificate(content::WebContents *webContents,
+base::OnceClosure ContentBrowserClientQt::SelectClientCertificate(content::BrowserContext *browser_context,
+ content::WebContents *webContents,
net::SSLCertRequestInfo *certRequestInfo,
net::ClientCertIdentityList clientCerts,
std::unique_ptr<content::ClientCertificateDelegate> delegate)
{
+ Q_UNUSED(browser_context);
if (!clientCerts.empty()) {
- WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
+ WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
QSharedPointer<ClientCertSelectController> certSelectController(
new ClientCertSelectController(certRequestInfo, std::move(clientCerts), std::move(delegate)));
@@ -526,7 +513,7 @@ void ContentBrowserClientQt::RegisterAssociatedInterfaceBindersForRenderFrameHos
base::BindRepeating(
[](content::RenderFrameHost *render_frame_host,
mojo::PendingAssociatedReceiver<pdf::mojom::PdfService> receiver) {
- pdf::PDFWebContentsHelper::BindPdfService(std::move(receiver), render_frame_host);
+ pdf::PDFDocumentHelper::BindPdfService(std::move(receiver), render_frame_host, std::make_unique<PDFDocumentHelperClientQt>());
}, &rfh));
#endif // BUILDFLAG(ENABLE_PDF)
ContentBrowserClient::RegisterAssociatedInterfaceBindersForRenderFrameHost(rfh, associated_registry);
@@ -978,11 +965,14 @@ void ContentBrowserClientQt::OverrideURLLoaderFactoryParams(content::BrowserCont
std::string ContentBrowserClientQt::getUserAgent()
{
// Mention the Chromium version we're based on to get passed stupid UA-string-based feature detection (several WebRTC demos need this)
- return content::BuildUserAgentFromProduct("QtWebEngine/" QTWEBENGINECORE_VERSION_STR " Chrome/" CHROMIUM_VERSION);
+ return content::BuildUserAgentFromProduct("QtWebEngine/" + std::string(qWebEngineVersion())
+ + " Chrome/"
+ + std::string(qWebEngineChromiumVersion()));
}
-blink::UserAgentMetadata ContentBrowserClientQt::getUserAgentMetadata()
+blink::UserAgentMetadata ContentBrowserClientQt::GetUserAgentMetadata()
{
+ // Implemented only for safe-keeping. It will be overridden on WebContents level.
static blink::UserAgentMetadata userAgentMetadata(embedder_support::GetUserAgentMetadata());
return userAgentMetadata;
}
@@ -1207,7 +1197,8 @@ bool ContentBrowserClientQt::WillCreateURLLoaderFactory(
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> *header_client,
bool *bypass_redirect_checks,
bool *disable_secure_dns,
- network::mojom::URLLoaderFactoryOverridePtr *factory_override)
+ network::mojom::URLLoaderFactoryOverridePtr *factory_override,
+ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner)
{
Q_UNUSED(render_process_id);
Q_UNUSED(type);
@@ -1223,6 +1214,7 @@ bool ContentBrowserClientQt::WillCreateURLLoaderFactory(
mojo::PendingRemote<network::mojom::URLLoaderFactory> pending_url_loader_factory;
*factory_receiver = pending_url_loader_factory.InitWithNewPipeAndPassReceiver();
// Will manage its own lifetime
+ // FIXME: use navigation_response_task_runner?
new ProxyingURLLoaderFactoryQt(adapter,
frame ? frame->GetFrameTreeNodeId() : content::RenderFrameHost::kNoFrameTreeNodeId,
std::move(proxied_receiver), std::move(pending_url_loader_factory));
@@ -1231,7 +1223,8 @@ bool ContentBrowserClientQt::WillCreateURLLoaderFactory(
std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
ContentBrowserClientQt::WillCreateURLLoaderRequestInterceptors(content::NavigationUIData* navigation_ui_data,
- int frame_tree_node_id)
+ int frame_tree_node_id, int64_t navigation_id,
+ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner)
{
std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> interceptors;
#if BUILDFLAG(ENABLE_PDF) && BUILDFLAG(ENABLE_EXTENSIONS)
@@ -1320,30 +1313,19 @@ void ContentBrowserClientQt::SiteInstanceGotProcess(content::SiteInstance *site_
#if BUILDFLAG(ENABLE_EXTENSIONS)
content::BrowserContext *context = site_instance->GetBrowserContext();
extensions::ExtensionRegistry *registry = extensions::ExtensionRegistry::Get(context);
- const extensions::Extension *extension = registry->enabled_extensions().GetExtensionOrAppByURL(site_instance->GetSiteURL());
- if (!extension)
+ if (!registry)
return;
-
- extensions::ProcessMap *processMap = extensions::ProcessMap::Get(context);
- processMap->Insert(extension->id(), site_instance->GetProcess()->GetID(), site_instance->GetId());
-#endif
-}
-
-void ContentBrowserClientQt::SiteInstanceDeleting(content::SiteInstance *site_instance)
-{
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- // Don't do anything if we're shutting down.
- if (content::BrowserMainRunner::ExitedMainMessageLoop() || !site_instance->HasProcess())
- return;
-
- content::BrowserContext *context = site_instance->GetBrowserContext();
- extensions::ExtensionRegistry *registry = extensions::ExtensionRegistry::Get(context);
- const extensions::Extension *extension = registry->enabled_extensions().GetExtensionOrAppByURL(site_instance->GetSiteURL());
+ if (site_instance->IsGuest())
+ return;
+ auto site_url = site_instance->GetSiteURL();
+ if (!site_url.SchemeIs(extensions::kExtensionScheme))
+ return;
+ const extensions::Extension *extension = registry->enabled_extensions().GetByID(site_url.host());
if (!extension)
return;
extensions::ProcessMap *processMap = extensions::ProcessMap::Get(context);
- processMap->Remove(extension->id(), site_instance->GetProcess()->GetID(), site_instance->GetId());
+ processMap->Insert(extension->id(), site_instance->GetProcess()->GetID());
#endif
}
@@ -1366,4 +1348,36 @@ ContentBrowserClientQt::AllowWebBluetooth(content::BrowserContext *browser_conte
return content::ContentBrowserClient::AllowWebBluetoothResult::BLOCK_GLOBALLY_DISABLED;
}
+content::WebAuthenticationDelegate *ContentBrowserClientQt::GetWebAuthenticationDelegate()
+{
+ static base::NoDestructor<WebAuthenticationDelegateQt> delegate;
+ return delegate.get();
+}
+
+#if !BUILDFLAG(IS_ANDROID)
+std::unique_ptr<content::AuthenticatorRequestClientDelegate>
+ContentBrowserClientQt::GetWebAuthenticationRequestDelegate(
+ content::RenderFrameHost *render_frame_host)
+{
+ return std::make_unique<AuthenticatorRequestClientDelegateQt>(render_frame_host);
+}
+#endif
+
+void ContentBrowserClientQt::GetMediaDeviceIDSalt(content::RenderFrameHost *rfh,
+ const net::SiteForCookies & /*site_for_cookies*/,
+ const blink::StorageKey & /*storage_key*/,
+ base::OnceCallback<void(bool, const std::string&)> callback)
+{
+#if BUILDFLAG(ENABLE_WEBRTC)
+ content::BrowserContext *browser_context = rfh->GetBrowserContext();
+ if (!browser_context->IsOffTheRecord()) {
+ ProfileQt *profile = static_cast<ProfileQt *>(browser_context);
+ std::string mediaId = profile->GetMediaDeviceIDSalt();
+ std::move(callback).Run(true, mediaId);
+ return;
+ }
+#endif
+ std::move(callback).Run(false, "");
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h
index b81b96ce1..7d8e98028 100644
--- a/src/core/content_browser_client_qt.h
+++ b/src/core/content_browser_client_qt.h
@@ -28,14 +28,9 @@ namespace device {
class GeolocationManager;
} // namespace device
-namespace gl {
-class GLShareGroup;
-}
-
namespace QtWebEngineCore {
class BrowserMainPartsQt;
-class ShareGroupQt;
class ContentBrowserClientQt : public content::ContentBrowserClient
{
@@ -44,7 +39,6 @@ public:
~ContentBrowserClientQt();
std::unique_ptr<content::BrowserMainParts> CreateBrowserMainParts(bool is_integration_test) override;
void RenderProcessWillLaunch(content::RenderProcessHost *host) override;
- gl::GLShareGroup* GetInProcessGpuShareGroup() override;
content::MediaObserver* GetMediaObserver() override;
void OverrideWebkitPrefs(content::WebContents *web_contents,
blink::web_pref::WebPreferences *prefs) override;
@@ -55,7 +49,8 @@ public:
bool is_main_frame_request,
bool strict_enforcement,
base::OnceCallback<void(content::CertificateRequestResultType)> callback) override;
- base::OnceClosure SelectClientCertificate(content::WebContents* web_contents,
+ base::OnceClosure SelectClientCertificate(content::BrowserContext* browser_context,
+ content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
net::ClientCertIdentityList client_certs,
std::unique_ptr<content::ClientCertificateDelegate> delegate) override;
@@ -193,7 +188,9 @@ public:
const std::string &scheme) override;
std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>>
WillCreateURLLoaderRequestInterceptors(content::NavigationUIData *navigation_ui_data,
- int frame_tree_node_id) override;
+ int frame_tree_node_id,
+ int64_t navigation_id,
+ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) override;
bool WillCreateURLLoaderFactory(content::BrowserContext *browser_context,
content::RenderFrameHost *frame,
int render_process_id,
@@ -205,7 +202,8 @@ public:
mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> *header_client,
bool *bypass_redirect_checks,
bool *disable_secure_dns,
- network::mojom::URLLoaderFactoryOverridePtr *factory_override) override;
+ network::mojom::URLLoaderFactoryOverridePtr *factory_override,
+ scoped_refptr<base::SequencedTaskRunner> navigation_response_task_runner) override;
scoped_refptr<network::SharedURLLoaderFactory> GetSystemSharedURLLoaderFactory() override;
network::mojom::NetworkContext *GetSystemNetworkContext() override;
void OnNetworkServiceCreated(network::mojom::NetworkService *network_service) override;
@@ -227,20 +225,28 @@ public:
void RegisterNonNetworkServiceWorkerUpdateURLLoaderFactories(content::BrowserContext* browser_context,
NonNetworkURLLoaderFactoryMap* factories) override;
void SiteInstanceGotProcess(content::SiteInstance *site_instance) override;
- void SiteInstanceDeleting(content::SiteInstance *site_instance) override;
base::flat_set<std::string> GetPluginMimeTypesWithExternalHandlers(content::BrowserContext *browser_context) override;
std::unique_ptr<content::WebContentsViewDelegate> GetWebContentsViewDelegate(content::WebContents *web_contents) override;
static std::string getUserAgent();
- static blink::UserAgentMetadata getUserAgentMetadata();
std::string GetUserAgent() override { return getUserAgent(); }
- blink::UserAgentMetadata GetUserAgentMetadata() override { return getUserAgentMetadata(); }
+ blink::UserAgentMetadata GetUserAgentMetadata() override;
std::string GetProduct() override;
+ content::WebAuthenticationDelegate *GetWebAuthenticationDelegate() override;
+#if !BUILDFLAG(IS_ANDROID)
+ std::unique_ptr<content::AuthenticatorRequestClientDelegate>
+ GetWebAuthenticationRequestDelegate(content::RenderFrameHost *render_frame_host) override;
+#endif
+
+ void GetMediaDeviceIDSalt(content::RenderFrameHost *rfh,
+ const net::SiteForCookies &site_for_cookies,
+ const blink::StorageKey &storage_key,
+ base::OnceCallback<void(bool, const std::string&)> callback) override;
+
private:
- scoped_refptr<ShareGroupQt> m_shareGroupQt;
BrowserMainPartsQt *m_browserMainParts = nullptr;
};
diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp
index 4a67dc029..b6a0909b0 100644
--- a/src/core/content_client_qt.cpp
+++ b/src/core/content_client_qt.cpp
@@ -30,8 +30,10 @@
#include <QLibraryInfo>
#include <QString>
+
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "media/cdm/cdm_paths.h" // nogncheck
+#include "media/cdm/clear_key_cdm_common.h"
#include "third_party/widevine/cdm/buildflags.h"
#include "third_party/widevine/cdm/widevine_cdm_common.h"
#if BUILDFLAG(ENABLE_WIDEVINE) && !BUILDFLAG(ENABLE_WIDEVINE_CDM_COMPONENT)
@@ -61,7 +63,7 @@ static QString webenginePluginsPath()
{
// Look for plugins in /plugins/webengine or application dir.
static bool initialized = false;
- static QString potentialPluginsPath = QLibraryInfo::location(QLibraryInfo::PluginsPath) % QLatin1String("/webengine");
+ static QString potentialPluginsPath = QLibraryInfo::path(QLibraryInfo::PluginsPath) % QLatin1String("/webengine");
if (!initialized) {
initialized = true;
if (!QFileInfo::exists(potentialPluginsPath))
@@ -105,7 +107,7 @@ static QString ppapiPluginsPath()
{
// Look for plugins in /plugins/ppapi or application dir.
static bool initialized = false;
- static QString potentialPluginsPath = QLibraryInfo::location(QLibraryInfo::PluginsPath) % QLatin1String("/ppapi");
+ static QString potentialPluginsPath = QLibraryInfo::path(QLibraryInfo::PluginsPath) % QLatin1String("/ppapi");
if (!initialized) {
initialized = true;
if (!QFileInfo::exists(potentialPluginsPath))
@@ -161,14 +163,17 @@ static const QDir widevineCdmDirHint(const QDir &widevineDir)
return widevineDir;
}
+ std::string error_message;
JSONStringValueDeserializer deserializer(jsonString);
- std::unique_ptr<base::Value> dict = deserializer.Deserialize(nullptr, nullptr);
+ std::unique_ptr<base::Value> dict = deserializer.Deserialize(nullptr, &error_message);
if (!dict || !dict->is_dict()) {
+ DLOG(ERROR) << "Could not deserialize the CDM hint file. Error: "
+ << error_message;
// Could not deserialize the CDM hint file.
return widevineDir;
}
- std::string *widevineCdmDirPath = dict->FindStringKey("Path");
+ std::string *widevineCdmDirPath = dict->GetDict().FindString("Path");
if (!widevineCdmDirPath)
return widevineDir;
@@ -353,31 +358,23 @@ void ContentClientQt::AddContentDecryptionModules(std::vector<content::CdmInfo>
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::FilePath clear_key_cdm_path = command_line->GetSwitchValuePath(switches::kClearKeyCdmPathForTesting);
if (!clear_key_cdm_path.empty() && base::PathExists(clear_key_cdm_path)) {
- // TODO(crbug.com/764480): Remove these after we have a central place for
- // External Clear Key (ECK) related information.
- // Normal External Clear Key key system.
- const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
- // A variant of ECK key system that has a different GUID.
- const char kExternalClearKeyDifferentGuidTestKeySystem[] =
- "org.chromium.externalclearkey.differentguid";
-
// Supported codecs are hard-coded in ExternalClearKeyProperties.
media::CdmCapability capability(
{}, {}, {media::EncryptionScheme::kCenc, media::EncryptionScheme::kCbcs},
{media::CdmSessionType::kTemporary,
media::CdmSessionType::kPersistentLicense});
- // Register kExternalClearKeyDifferentGuidTestKeySystem first separately.
+ // Register media::kExternalClearKeyDifferentCdmTypeTestKeySystem first separately.
// Otherwise, it'll be treated as a sub-key-system of normal
// kExternalClearKeyKeySystem. See MultipleCdmTypes test in
// ECKEncryptedMediaTest.
- cdms->push_back(content::CdmInfo(kExternalClearKeyDifferentGuidTestKeySystem,
+ cdms->push_back(content::CdmInfo(media::kExternalClearKeyDifferentCdmTypeTestKeySystem,
Robustness::kSoftwareSecure, capability,
/*supports_sub_key_systems=*/false, media::kClearKeyCdmDisplayName,
media::kClearKeyCdmDifferentCdmType, base::Version("0.1.0.0"),
clear_key_cdm_path));
- cdms->push_back(content::CdmInfo(kExternalClearKeyKeySystem,
+ cdms->push_back(content::CdmInfo(media::kExternalClearKeyKeySystem,
Robustness::kSoftwareSecure, capability,
/*supports_sub_key_systems=*/true, media::kClearKeyCdmDisplayName,
media::kClearKeyCdmType, base::Version("0.1.0.0"),
@@ -420,4 +417,19 @@ std::u16string ContentClientQt::GetLocalizedString(int message_id)
return l10n_util::GetStringUTF16(message_id);
}
+// This method is a copy from chrome/common/chrome_content_client.cc:
+// Copyright 2012 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.Chromium file.
+blink::OriginTrialPolicy *ContentClientQt::GetOriginTrialPolicy()
+{
+ // Prevent initialization race (see crbug.com/721144). There may be a
+ // race when the policy is needed for worker startup (which happens on a
+ // separate worker thread).
+ base::AutoLock auto_lock(origin_trial_policy_lock_);
+ if (!origin_trial_policy_)
+ origin_trial_policy_ = std::make_unique<embedder_support::OriginTrialPolicyImpl>();
+ return origin_trial_policy_.get();
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/content_client_qt.h b/src/core/content_client_qt.h
index 92d41b748..f58e17f96 100644
--- a/src/core/content_client_qt.h
+++ b/src/core/content_client_qt.h
@@ -5,10 +5,15 @@
#define CONTENT_CLIENT_QT_H
#include "qtwebenginecoreglobal_p.h"
+
#include "base/strings/string_piece.h"
+#include "base/synchronization/lock.h"
+#include "components/embedder_support/origin_trials/origin_trial_policy_impl.h"
#include "content/public/common/content_client.h"
#include "ui/base/layout.h"
+#include <memory>
+
namespace QtWebEngineCore {
class ContentClientQt : public content::ContentClient {
@@ -24,6 +29,12 @@ public:
base::RefCountedMemory* GetDataResourceBytes(int resource_id) override;
gfx::Image &GetNativeImageNamed(int resource_id) override;
std::u16string GetLocalizedString(int message_id) override;
+ blink::OriginTrialPolicy *GetOriginTrialPolicy() override;
+
+private:
+ // Used to lock when |origin_trial_policy_| is initialized.
+ base::Lock origin_trial_policy_lock_;
+ std::unique_ptr<embedder_support::OriginTrialPolicyImpl> origin_trial_policy_;
};
} // namespace QtWebEngineCore
diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp
index 52e23399e..f949d93a5 100644
--- a/src/core/content_main_delegate_qt.cpp
+++ b/src/core/content_main_delegate_qt.cpp
@@ -14,7 +14,6 @@
#include "content/public/browser/browser_main_runner.h"
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
-#include "media/gpu/buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/ui_base_paths.h"
#include "ui/base/resource/resource_bundle.h"
@@ -39,12 +38,9 @@
#include "ui/base/ui_base_switches.h"
#endif
-// must be included before vaapi_wrapper.h
-#include <QtCore/qcoreapplication.h>
-
#if BUILDFLAG(IS_WIN)
-#include "media/gpu/windows/dxva_video_decode_accelerator_win.h"
-#include "media/gpu/windows/media_foundation_video_encode_accelerator_win.h"
+#include "media/base/win/mf_initializer.h"
+#include "sandbox/policy/win/sandbox_warmup.h"
#endif
#if BUILDFLAG(IS_MAC)
@@ -53,9 +49,7 @@
#include "media/gpu/mac/vt_video_decode_accelerator_mac.h"
#endif
-#if BUILDFLAG(USE_VAAPI)
-#include "media/gpu/vaapi/vaapi_wrapper.h"
-#endif
+#include <QtCore/qcoreapplication.h>
namespace content {
ContentClient *GetContentClient();
@@ -89,7 +83,7 @@ struct LazyDirectoryListerCacher
webui::GetI18nTemplateHtml(
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(IDR_DIR_HEADER_HTML),
std::move(dict));
- html_data = base::RefCountedString::TakeString(&html);
+ html_data = base::MakeRefCounted<base::RefCountedString>(std::move(html));
}
scoped_refptr<base::RefCountedMemory> html_data;
@@ -171,21 +165,20 @@ void ContentMainDelegateQt::PreSandboxStartup()
setlocale(LC_NUMERIC, "C");
#endif
- // from gpu_main.cc:
-#if BUILDFLAG(USE_VAAPI)
- media::VaapiWrapper::PreSandboxInitialization();
-#endif
+ bool isBrowserProcess = !parsedCommandLine->HasSwitch(switches::kProcessType);
+ if (isBrowserProcess) {
+ // from gpu_main.cc:
#if BUILDFLAG(IS_WIN)
- media::DXVAVideoDecodeAccelerator::PreSandboxInitialization();
- media::MediaFoundationVideoEncodeAccelerator::PreSandboxInitialization();
+ media::PreSandboxMediaFoundationInitialization();
#endif
#if BUILDFLAG(IS_MAC)
- {
- TRACE_EVENT0("gpu", "Initialize VideoToolbox");
- media::InitializeVideoToolbox();
- }
+ {
+ TRACE_EVENT0("gpu", "Initialize VideoToolbox");
+ media::InitializeVideoToolbox();
+ }
#endif
+ }
if (parsedCommandLine->HasSwitch(switches::kApplicationName)) {
std::string appName = parsedCommandLine->GetSwitchValueASCII(switches::kApplicationName);
@@ -262,6 +255,8 @@ absl::optional<int> ContentMainDelegateQt::BasicStartupComplete()
{
SafeOverridePath(base::FILE_EXE, WebEngineLibraryInfo::getPath(base::FILE_EXE));
SafeOverridePath(base::DIR_QT_LIBRARY_DATA, WebEngineLibraryInfo::getPath(base::DIR_QT_LIBRARY_DATA));
+ SafeOverridePath(base::DIR_ASSETS, WebEngineLibraryInfo::getPath(base::DIR_ASSETS));
+ SafeOverridePath(base::DIR_EXE, WebEngineLibraryInfo::getPath(base::DIR_ASSETS));
SafeOverridePath(ui::DIR_LOCALES, WebEngineLibraryInfo::getPath(ui::DIR_LOCALES));
#if QT_CONFIG(webengine_spellchecker)
SafeOverridePath(base::DIR_APP_DICTIONARIES, WebEngineLibraryInfo::getPath(base::DIR_APP_DICTIONARIES));
diff --git a/src/core/desktop_media_controller.cpp b/src/core/desktop_media_controller.cpp
new file mode 100644
index 000000000..50ac0a40c
--- /dev/null
+++ b/src/core/desktop_media_controller.cpp
@@ -0,0 +1,244 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "desktop_media_controller.h"
+#include "desktop_media_controller_p.h"
+#include "type_conversion.h"
+
+#include "base/containers/contains.h"
+#include "base/functional/callback.h"
+#include "chrome/browser/media/webrtc/desktop_capturer_wrapper.h"
+#include "chrome/browser/media/webrtc/native_desktop_media_list.h"
+#include "content/public/browser/desktop_media_id.h"
+
+#if QT_CONFIG(webengine_webrtc)
+#include "content/public/browser/desktop_capture.h"
+#endif // QT_CONFIG(webengine_webrtc)
+
+namespace QtWebEngineCore {
+namespace {
+DesktopMediaList::Type toMediaListType(DesktopMediaType type)
+{
+ switch (type) {
+ case DesktopMediaType::Screen:
+ return DesktopMediaList::Type::kScreen;
+ case DesktopMediaType::Window:
+ return DesktopMediaList::Type::kWindow;
+ default:
+ return DesktopMediaList::Type::kNone;
+ }
+}
+
+std::unique_ptr<DesktopMediaList> createMediaList(DesktopMediaType type)
+{
+#if QT_CONFIG(webengine_webrtc)
+ DesktopMediaList::Type listType = toMediaListType(type);
+ webrtc::DesktopCaptureOptions options = content::desktop_capture::CreateDesktopCaptureOptions();
+
+ switch (listType) {
+ case DesktopMediaList::Type::kScreen: {
+ std::unique_ptr<webrtc::DesktopCapturer> screenCapturer =
+ webrtc::DesktopCapturer::CreateScreenCapturer(options);
+ std::unique_ptr<DesktopCapturerWrapper> capturer =
+ std::make_unique<DesktopCapturerWrapper>(std::move(screenCapturer));
+ return std::make_unique<NativeDesktopMediaList>(listType, std::move(capturer));
+ }
+ case DesktopMediaList::Type::kWindow: {
+ std::unique_ptr<webrtc::DesktopCapturer> windowCapturer =
+ webrtc::DesktopCapturer::CreateWindowCapturer(options);
+ std::unique_ptr<DesktopCapturerWrapper> capturer =
+ std::make_unique<DesktopCapturerWrapper>(std::move(windowCapturer));
+ return std::make_unique<NativeDesktopMediaList>(
+ listType, std::move(capturer),
+ !content::desktop_capture::ShouldEnumerateCurrentProcessWindows());
+ }
+ default: {
+ Q_UNREACHABLE();
+ }
+ }
+#else
+ return nullptr;
+#endif // QT_CONFIG(webengine_webrtc)
+}
+} // namespace
+
+class DesktopMediaListQtPrivate : public DesktopMediaListObserver
+{
+public:
+ DesktopMediaListQtPrivate(DesktopMediaType type, DesktopMediaListQt *qq);
+
+ void init();
+ void startUpdating();
+ const DesktopMediaList::Source& getSource(int index) const;
+
+ void OnSourceAdded(int index) override;
+ void OnSourceRemoved(int index) override;
+ void OnSourceMoved(int old_index, int new_index) override;
+ void OnSourceNameChanged(int index) override;
+ void OnSourceThumbnailChanged(int index) override { }
+ void OnSourcePreviewChanged(size_t index) override { }
+ void OnDelegatedSourceListSelection() override { }
+ void OnDelegatedSourceListDismissed() override { }
+
+ bool isInitialized;
+ std::unique_ptr<DesktopMediaList> mediaList;
+ DesktopMediaListQt *q_ptr;
+ Q_DECLARE_PUBLIC(DesktopMediaListQt)
+};
+
+DesktopMediaListQtPrivate::DesktopMediaListQtPrivate(DesktopMediaType type, DesktopMediaListQt *qq)
+ : isInitialized(false)
+ , mediaList(createMediaList(type))
+ , q_ptr(qq)
+{
+}
+
+const DesktopMediaList::Source& DesktopMediaListQtPrivate::getSource(int index) const
+{
+ return mediaList->GetSource(index);
+}
+
+void DesktopMediaListQtPrivate::init()
+{
+ // Work around the asynchronous initialization of the source list.
+ // DesktopMediaList::Update populates the list and notifies the controller when it completes.
+ // This makes direct 'selectScreen/Window' calls possible from the frontend.
+ // Note: StartUpdating should be called after Update is completed as it can overwrite the
+ // internal cb.
+ base::OnceCallback<void()> onComplete = base::BindOnce(
+ [](DesktopMediaListQtPrivate *observer) {
+ observer->isInitialized = true;
+ Q_EMIT observer->q_ptr->initialized();
+ observer->startUpdating();
+ },
+ this);
+ mediaList->Update(std::move(onComplete));
+}
+
+void DesktopMediaListQtPrivate::startUpdating()
+{
+ mediaList->StartUpdating(this);
+}
+
+void DesktopMediaListQtPrivate::OnSourceAdded(int index)
+{
+ Q_Q(DesktopMediaListQt);
+ Q_EMIT q->sourceAdded(index);
+}
+
+void DesktopMediaListQtPrivate::OnSourceRemoved(int index)
+{
+ Q_Q(DesktopMediaListQt);
+ Q_EMIT q->sourceRemoved(index);
+}
+
+void DesktopMediaListQtPrivate::OnSourceMoved(int old_index, int new_index)
+{
+ Q_Q(DesktopMediaListQt);
+ Q_EMIT q->sourceMoved(old_index, new_index);
+}
+
+void DesktopMediaListQtPrivate::OnSourceNameChanged(int index)
+{
+ Q_Q(DesktopMediaListQt);
+ Q_EMIT q->sourceNameChanged(index);
+}
+
+DesktopMediaListQt::DesktopMediaListQt(DesktopMediaType type)
+ : d(new DesktopMediaListQtPrivate(type, this))
+{
+}
+
+DesktopMediaListQt::~DesktopMediaListQt() { }
+
+QString DesktopMediaListQt::getSourceName(int index) const
+{
+ const auto &source = d->getSource(index);
+ return toQt(source.name);
+}
+
+int DesktopMediaListQt::getSourceCount() const
+{
+ return d->mediaList->GetSourceCount();
+}
+
+bool DesktopMediaListQt::isInitialized() const
+{
+ return d->isInitialized;
+}
+
+DesktopMediaControllerPrivate::DesktopMediaControllerPrivate(
+ base::OnceCallback<void(content::DesktopMediaID)> doneCallback)
+ : doneCallback(std::move(doneCallback))
+ , screens(new DesktopMediaListQt(DesktopMediaType::Screen))
+ , windows(new DesktopMediaListQt(DesktopMediaType::Window))
+{
+}
+
+void DesktopMediaControllerPrivate::selectScreen(int index)
+{
+ const auto &source = screens->d->getSource(index);
+ std::move(doneCallback).Run(source.id);
+}
+
+void DesktopMediaControllerPrivate::selectWindow(int index)
+{
+ const auto &source = windows->d->getSource(index);
+ std::move(doneCallback).Run(source.id);
+}
+
+void DesktopMediaControllerPrivate::cancel()
+{
+ std::move(doneCallback).Run({});
+}
+
+DesktopMediaController::DesktopMediaController(DesktopMediaControllerPrivate *dd)
+ : d(dd)
+{
+ // Make sure both lists are populated before sending the request.
+ DesktopMediaListQt *screens = DesktopMediaController::screens();
+ DesktopMediaListQt *windows = DesktopMediaController::windows();
+ QObject::connect(screens, &DesktopMediaListQt::initialized, [windows, this]() {
+ if (windows->isInitialized())
+ Q_EMIT mediaListsInitialized();
+ });
+
+ QObject::connect(windows, &DesktopMediaListQt::initialized, [screens, this]() {
+ if (screens->isInitialized())
+ Q_EMIT mediaListsInitialized();
+ });
+
+ screens->d->init();
+ windows->d->init();
+}
+
+DesktopMediaController::~DesktopMediaController()
+{
+}
+
+void DesktopMediaController::selectScreen(int index)
+{
+ d->selectScreen(index);
+}
+
+void DesktopMediaController::selectWindow(int index)
+{
+ d->selectWindow(index);
+}
+
+void DesktopMediaController::cancel()
+{
+ d->cancel();
+}
+
+DesktopMediaListQt *DesktopMediaController::screens() const
+{
+ return d->screens.data();
+}
+
+DesktopMediaListQt *DesktopMediaController::windows() const
+{
+ return d->windows.data();
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/desktop_media_controller.h b/src/core/desktop_media_controller.h
new file mode 100644
index 000000000..0cb741225
--- /dev/null
+++ b/src/core/desktop_media_controller.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef DESKTOP_MEDIA_CONTROLLER_H
+#define DESKTOP_MEDIA_CONTROLLER_H
+
+#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+#include <QtCore/QObject>
+
+#include <QString>
+
+namespace QtWebEngineCore {
+class DesktopMediaListQtPrivate;
+class DesktopMediaControllerPrivate;
+
+enum DesktopMediaType { Screen = 0, Window };
+
+class Q_WEBENGINECORE_EXPORT DesktopMediaListQt : public QObject
+{
+ Q_OBJECT
+public:
+ ~DesktopMediaListQt() override;
+
+ QString getSourceName(int index) const;
+ int getSourceCount() const;
+
+Q_SIGNALS:
+ void initialized();
+ void itemSelected(int index);
+ void sourceAdded(int index);
+ void sourceRemoved(int index);
+ void sourceMoved(int oldIndex, int newIndex);
+ void sourceNameChanged(int index);
+
+private:
+ friend class DesktopMediaController;
+ friend class DesktopMediaControllerPrivate;
+ bool isInitialized() const;
+ explicit DesktopMediaListQt(DesktopMediaType type);
+ std::unique_ptr<DesktopMediaListQtPrivate> d;
+};
+
+class Q_WEBENGINECORE_EXPORT DesktopMediaController : public QObject
+{
+ Q_OBJECT
+public:
+ explicit DesktopMediaController(DesktopMediaControllerPrivate *dd);
+ ~DesktopMediaController() override;
+
+ DesktopMediaListQt *screens() const;
+ DesktopMediaListQt *windows() const;
+
+ void selectScreen(int index);
+ void selectWindow(int index);
+ void cancel();
+
+Q_SIGNALS:
+ void mediaListsInitialized();
+
+private:
+ std::unique_ptr<DesktopMediaControllerPrivate> d;
+};
+
+} // namespace QtWebEngineCore
+#endif // DESKTOP_MEDIA_CONTROLLER_H
diff --git a/src/core/desktop_media_controller_p.h b/src/core/desktop_media_controller_p.h
new file mode 100644
index 000000000..4bb3a6312
--- /dev/null
+++ b/src/core/desktop_media_controller_p.h
@@ -0,0 +1,28 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef DESKTOP_MEDIA_CONTROLLER_P_H
+#define DESKTOP_MEDIA_CONTROLLER_P_H
+
+#include <QtCore/QObject>
+#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+
+#include "content/public/browser/desktop_media_id.h"
+#include "base/functional/callback.h"
+
+namespace QtWebEngineCore {
+class Q_WEBENGINECORE_EXPORT DesktopMediaControllerPrivate
+{
+public:
+ DesktopMediaControllerPrivate(base::OnceCallback<void(content::DesktopMediaID)> doneCallback);
+ void selectScreen(int index);
+ void selectWindow(int index);
+ void cancel();
+ base::OnceCallback<void(content::DesktopMediaID)> doneCallback;
+ QScopedPointer<DesktopMediaListQt> screens;
+ QScopedPointer<DesktopMediaListQt> windows;
+};
+
+} // namespace QtWebEngineCore
+
+#endif // DESKTOP_MEDIA_CONTROLLER_P_H
diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp
index 73698e263..7cea68390 100644
--- a/src/core/devtools_frontend_qt.cpp
+++ b/src/core/devtools_frontend_qt.cpp
@@ -8,171 +8,44 @@
#include "devtools_frontend_qt.h"
-#include "profile_adapter.h"
#include "profile_qt.h"
#include "web_contents_adapter.h"
+#include "web_contents_delegate_qt.h"
-#include "base/base64.h"
-#include "base/json/json_reader.h"
-#include "base/json/json_writer.h"
-#include "base/json/string_escape.h"
-#include "base/memory/ptr_util.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
#include "chrome/browser/devtools/devtools_eye_dropper.h"
-#include "chrome/browser/devtools/devtools_file_helper.h"
-#include "chrome/common/url_constants.h"
-#include "components/prefs/in_memory_pref_store.h"
-#include "components/prefs/json_pref_store.h"
+#include "chrome/browser/devtools/devtools_ui_bindings.h"
+#include "chrome/common/pref_names.h"
+#include "components/prefs/scoped_user_pref_update.h"
#include "content/public/browser/browser_context.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/devtools_frontend_host.h"
-#include "content/public/browser/file_url_loader.h"
+#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/navigation_controller.h"
-#include "content/public/browser/navigation_handle.h"
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/shared_cors_origin_access_list.h"
-#include "content/public/browser/storage_partition.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/common/content_client.h"
-#include "content/public/common/url_constants.h"
-#include "content/public/common/url_utils.h"
-#include "ipc/ipc_channel.h"
-#include "net/http/http_response_headers.h"
-#include "net/traffic_annotation/network_traffic_annotation.h"
-#include "services/network/public/cpp/simple_url_loader.h"
-#include "services/network/public/cpp/simple_url_loader_stream_consumer.h"
+#include "content/public/browser/page_navigator.h"
+#include "content/public/browser/site_instance.h"
+#include "url/gurl.h"
using namespace QtWebEngineCore;
namespace {
-
-constexpr char kScreencastEnabled[] = "screencastEnabled";
-
-base::DictionaryValue CreateFileSystemValue(DevToolsFileHelper::FileSystem fileSystem)
-{
- base::DictionaryValue fileSystemValue;
- fileSystemValue.SetStringKey("type", fileSystem.type);
- fileSystemValue.SetStringKey("fileSystemName", fileSystem.file_system_name);
- fileSystemValue.SetStringKey("rootURL", fileSystem.root_url);
- fileSystemValue.SetStringKey("fileSystemPath", fileSystem.file_system_path);
- return fileSystemValue;
-}
-
-base::DictionaryValue BuildObjectForResponse(const net::HttpResponseHeaders *rh, bool success,
- int netError)
-{
- base::DictionaryValue response;
- int responseCode = 200;
- if (rh) {
- responseCode = rh->response_code();
- } else if (!success) {
- // In case of no headers, assume file:// URL and failed to load
- responseCode = 404;
- }
- response.SetInteger("statusCode", responseCode);
- response.SetInteger("netError", netError);
- response.SetString("netErrorName", net::ErrorToString(netError));
-
- auto headers = std::make_unique<base::DictionaryValue>();
- size_t iterator = 0;
- std::string name;
- std::string value;
- // TODO(caseq): this probably needs to handle duplicate header names
- // correctly by folding them.
- while (rh && rh->EnumerateHeaderLines(&iterator, &name, &value))
- headers->SetString(name, value);
-
- response.Set("headers", std::move(headers));
- return response;
-}
+static const char kScreencastEnabled[] = "screencastEnabled";
static std::string GetFrontendURL()
{
return "devtools://devtools/bundled/inspector.html";
}
-
-} // namespace
+} // namespace
namespace QtWebEngineCore {
-class DevToolsFrontendQt::NetworkResourceLoader
- : public network::SimpleURLLoaderStreamConsumer {
-public:
- NetworkResourceLoader(int stream_id,
- int request_id,
- DevToolsFrontendQt *bindings,
- std::unique_ptr<network::SimpleURLLoader> loader,
- network::mojom::URLLoaderFactory *url_loader_factory)
- : stream_id_(stream_id),
- request_id_(request_id),
- bindings_(bindings),
- loader_(std::move(loader))
- {
- loader_->SetOnResponseStartedCallback(base::BindOnce(
- &NetworkResourceLoader::OnResponseStarted, base::Unretained(this)));
- loader_->DownloadAsStream(url_loader_factory, this);
- }
-
-private:
- void OnResponseStarted(const GURL &final_url,
- const network::mojom::URLResponseHead &response_head)
- {
- response_headers_ = response_head.headers;
- }
-
- void OnDataReceived(base::StringPiece chunk, base::OnceClosure resume) override
- {
- base::Value chunkValue;
-
- bool encoded = !base::IsStringUTF8(chunk);
- if (encoded) {
- std::string encoded_string;
- base::Base64Encode(chunk, &encoded_string);
- chunkValue = base::Value(std::move(encoded_string));
- } else {
- chunkValue = base::Value(chunk);
- }
- base::Value id(stream_id_);
- base::Value encodedValue(encoded);
-
- bindings_->CallClientFunction("DevToolsAPI", "streamWrite", std::move(id), std::move(chunkValue), std::move(encodedValue));
- std::move(resume).Run();
- }
-
- void OnComplete(bool success) override
- {
- auto response = BuildObjectForResponse(response_headers_.get(), success, loader_->NetError());
- bindings_->SendMessageAck(request_id_, std::move(response));
- bindings_->m_loaders.erase(bindings_->m_loaders.find(this));
- }
-
- void OnRetry(base::OnceClosure start_retry) override { NOTREACHED(); }
-
- const int stream_id_;
- const int request_id_;
- DevToolsFrontendQt *const bindings_;
- std::unique_ptr<network::SimpleURLLoader> loader_;
- scoped_refptr<net::HttpResponseHeaders> response_headers_;
-};
-
-// This constant should be in sync with
-// the constant at devtools_ui_bindings.cc.
-const size_t kMaxMessageChunkSize = IPC::Channel::kMaximumMessageSize / 4;
-
// static
-DevToolsFrontendQt *DevToolsFrontendQt::Show(QSharedPointer<WebContentsAdapter> frontendAdapter, content::WebContents *inspectedContents)
+DevToolsFrontendQt *DevToolsFrontendQt::Show(QSharedPointer<WebContentsAdapter> frontendAdapter,
+ content::WebContents *inspectedContents)
{
DCHECK(frontendAdapter);
DCHECK(inspectedContents);
if (!frontendAdapter->isInitialized()) {
- scoped_refptr<content::SiteInstance> site =
- content::SiteInstance::CreateForURL(frontendAdapter->profile(), GURL(GetFrontendURL()));
+ scoped_refptr<content::SiteInstance> site = content::SiteInstance::CreateForURL(
+ frontendAdapter->profile(), GURL(GetFrontendURL()));
frontendAdapter->initialize(site.get());
}
@@ -184,13 +57,15 @@ DevToolsFrontendQt *DevToolsFrontendQt::Show(QSharedPointer<WebContentsAdapter>
return nullptr;
}
- DevToolsFrontendQt *devtoolsFrontend = new DevToolsFrontendQt(frontendAdapter, inspectedContents);
+ DevToolsFrontendQt *devtoolsFrontend =
+ new DevToolsFrontendQt(frontendAdapter, inspectedContents);
if (contents->GetURL() == GURL(GetFrontendURL())) {
- contents->GetController().Reload(content::ReloadType::ORIGINAL_REQUEST_URL, false);
- } else {
+ contents->GetController().LoadOriginalRequestURL();
+ } else {
content::NavigationController::LoadURLParams loadParams((GURL(GetFrontendURL())));
- loadParams.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_TOPLEVEL | ui::PAGE_TRANSITION_FROM_API);
+ loadParams.transition_type = ui::PageTransitionFromInt(ui::PAGE_TRANSITION_AUTO_TOPLEVEL
+ | ui::PAGE_TRANSITION_FROM_API);
contents->GetController().LoadURLWithParams(loadParams);
}
@@ -201,25 +76,21 @@ DevToolsFrontendQt::DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webCon
content::WebContents *inspectedContents)
: content::WebContentsObserver(webContentsAdapter->webContents())
, m_frontendAdapter(webContentsAdapter)
- , m_inspectedAdapter(static_cast<WebContentsDelegateQt *>(inspectedContents->GetDelegate())
- ->webContentsAdapter())
, m_inspectedContents(inspectedContents)
- , m_inspect_element_at_x(-1)
- , m_inspect_element_at_y(-1)
- , m_prefStore(nullptr)
- , m_weakFactory(this)
+ , m_outermostContents(inspectedContents->GetOutermostWebContents())
+ , m_bindings(new DevToolsUIBindings(webContentsAdapter->webContents()))
{
- // We use a separate prefstore than one in ProfileQt, because that one is in-memory only, and this
- // needs to be stored or it will show introduction text on every load.
- if (webContentsAdapter->profileAdapter()->isOffTheRecord())
- m_prefStore = scoped_refptr<PersistentPrefStore>(new InMemoryPrefStore());
- else
- CreateJsonPreferences(false);
-
- m_frontendDelegate = static_cast<WebContentsDelegateQt *>(webContentsAdapter->webContents()->GetDelegate());
- m_fileHelper = std::make_unique<DevToolsFileHelper>(
- webContentsAdapter->webContents(),
- static_cast<Profile *>(webContentsAdapter->webContents()->GetBrowserContext()), this);
+ // bindings take ownership over devtools
+ m_bindings->SetDelegate(this);
+ m_bindings->AttachTo(content::DevToolsAgentHost::GetOrCreateFor(m_inspectedContents));
+
+ auto *prefService = m_bindings->profile()->GetPrefs();
+ const auto &devtoolsPrefs = prefService->GetDict(prefs::kDevToolsPreferences);
+
+ if (!devtoolsPrefs.Find(kScreencastEnabled)) {
+ ScopedDictPrefUpdate update(prefService, prefs::kDevToolsPreferences);
+ update->Set(kScreencastEnabled, "false");
+ }
}
DevToolsFrontendQt::~DevToolsFrontendQt()
@@ -230,7 +101,7 @@ DevToolsFrontendQt::~DevToolsFrontendQt()
void DevToolsFrontendQt::Activate()
{
- m_frontendDelegate->ActivateContents(web_contents());
+ web_contents()->GetDelegate()->ActivateContents(web_contents());
}
void DevToolsFrontendQt::Focus()
@@ -240,12 +111,11 @@ void DevToolsFrontendQt::Focus()
void DevToolsFrontendQt::InspectElementAt(int x, int y)
{
- if (m_agentHost)
- m_agentHost->InspectElement(m_inspectedContents->GetFocusedFrame(), x, y);
- else {
- m_inspect_element_at_x = x;
- m_inspect_element_at_y = y;
- }
+ if (!m_inspectedContents)
+ return;
+ scoped_refptr<content::DevToolsAgentHost> agent(
+ content::DevToolsAgentHost::GetOrCreateFor(m_inspectedContents));
+ agent->InspectElement(m_inspectedContents->GetFocusedFrame(), x, y);
}
void DevToolsFrontendQt::Close()
@@ -256,314 +126,56 @@ void DevToolsFrontendQt::Close()
void DevToolsFrontendQt::DisconnectFromTarget()
{
- if (!m_agentHost)
- return;
- m_agentHost->DetachClient(this);
- m_agentHost = nullptr;
+ m_bindings->Detach();
}
-void DevToolsFrontendQt::ReadyToCommitNavigation(content::NavigationHandle *navigationHandle)
+WebContentsDelegateQt *DevToolsFrontendQt::frontendDelegate() const
{
- // ShellDevToolsFrontend does this in RenderViewCreated,
- // but that doesn't work for us for some reason.
- content::RenderFrameHost *frame = navigationHandle->GetRenderFrameHost();
- if (navigationHandle->IsInMainFrame()) {
- // If the frontend for some reason goes to some place other than devtools, stop the bindings
- if (navigationHandle->GetURL() != GetFrontendURL())
- m_frontendHost.reset(nullptr);
- else if (!m_frontendHost)
- m_frontendHost = content::DevToolsFrontendHost::Create(
- frame,
- base::BindRepeating(&DevToolsFrontendQt::HandleMessageFromDevToolsFrontend,
- base::Unretained(this)));
- }
+ return static_cast<WebContentsDelegateQt *>(web_contents()->GetDelegate());
}
-void DevToolsFrontendQt::DocumentOnLoadCompletedInPrimaryMainFrame()
+void DevToolsFrontendQt::ColorPickedInEyeDropper(int r, int g, int b, int a)
{
- if (!m_inspectedContents)
- return;
- // Don't call AttachClient multiple times for the same DevToolsAgentHost.
- // Otherwise it will call AgentHostClosed which closes the DevTools window.
- // This may happen in cases where the DevTools content fails to load.
- scoped_refptr<content::DevToolsAgentHost> agent_host =
- content::DevToolsAgentHost::GetOrCreateFor(m_inspectedContents);
- if (agent_host != m_agentHost) {
- if (m_agentHost)
- m_agentHost->DetachClient(this);
- m_agentHost = agent_host;
- m_agentHost->AttachClient(this);
- if (m_inspect_element_at_x != -1) {
- m_agentHost->InspectElement(m_inspectedContents->GetFocusedFrame(), m_inspect_element_at_x, m_inspect_element_at_y);
- m_inspect_element_at_x = -1;
- m_inspect_element_at_y = -1;
- }
- }
+ base::Value::Dict color;
+ color.Set("r", r);
+ color.Set("g", g);
+ color.Set("b", b);
+ color.Set("a", a);
+ m_bindings->CallClientMethod("DevToolsAPI", "eyeDropperPickedColor", base::Value(std::move(color)));
}
+// content::WebContentsObserver implementation
void DevToolsFrontendQt::WebContentsDestroyed()
{
- if (m_inspectedAdapter)
- m_inspectedAdapter->devToolsFrontendDestroyed(this);
-
- if (m_agentHost) {
- m_agentHost->DetachClient(this);
- m_agentHost = nullptr;
- }
- delete this;
-}
-
-void DevToolsFrontendQt::SetPreference(const std::string &name, const std::string &value)
-{
- DCHECK(m_prefStore);
- m_prefStore->SetValue(name, base::Value(value), 0);
-}
+ // If m_inspectedContents was a guest view it was probably already destroyed,
+ // but its embedder still lives.
+ WebContentsAdapter *inspectedAdapter =
+ static_cast<WebContentsDelegateQt *>(m_outermostContents->GetDelegate())
+ ->webContentsAdapter();
+ if (inspectedAdapter)
+ inspectedAdapter->devToolsFrontendDestroyed(this);
-void DevToolsFrontendQt::RemovePreference(const std::string &name)
-{
- DCHECK(m_prefStore);
- m_prefStore->RemoveValue(name, 0);
+ delete m_bindings; // it will call ~DevToolsFrontendQt()
}
-void DevToolsFrontendQt::ClearPreferences()
+// DevToolsUIBindings::Delegate implementation
+void DevToolsFrontendQt::ActivateWindow()
{
- ProfileQt *profile = static_cast<ProfileQt *>(web_contents()->GetBrowserContext());
- if (profile->IsOffTheRecord() || profile->profileAdapter()->storageName().isEmpty())
- m_prefStore = scoped_refptr<PersistentPrefStore>(new InMemoryPrefStore());
- else
- CreateJsonPreferences(true);
+ web_contents()->Focus();
}
-void DevToolsFrontendQt::CreateJsonPreferences(bool clear)
+void DevToolsFrontendQt::OnLoadCompleted()
{
- content::BrowserContext *browserContext = web_contents()->GetBrowserContext();
- DCHECK(!browserContext->IsOffTheRecord());
- JsonPrefStore *jsonPrefStore = new JsonPrefStore(
- browserContext->GetPath().Append(FILE_PATH_LITERAL("devtoolsprefs.json")));
- // We effectively clear the preferences by not calling ReadPrefs
- base::ScopedAllowBlockingForTesting allowBlocking;
- if (!clear)
- jsonPrefStore->ReadPrefs();
-
- m_prefStore = scoped_refptr<PersistentPrefStore>(jsonPrefStore);
+ m_bindings->CallClientMethod("DevToolsAPI", "setUseSoftMenu", base::Value(true));
}
-void DevToolsFrontendQt::HandleMessageFromDevToolsFrontend(base::Value::Dict message)
+void DevToolsFrontendQt::OpenInNewTab(const std::string &url)
{
- const base::Value *method_ptr = nullptr;
- base::Value *params_value = nullptr;
- method_ptr = message.Find("method");
- params_value = message.Find("params");
- if (!method_ptr || !method_ptr->is_string() || (params_value && !params_value->is_list())) {
- LOG(ERROR) << "Invalid message was sent to embedder: " << message;
- return;
- }
- base::Value empty_params(base::Value::Type::LIST);
- if (!params_value)
- params_value = &empty_params;
-
- int request_id = message.Find("id")->GetIfInt().value_or(0);
- const std::string &method = *method_ptr->GetIfString();
- base::Value::List *paramsPtr;
- if (params_value)
- paramsPtr = params_value->GetIfList();
- base::Value::List &params = *paramsPtr;
-
- if (method == "dispatchProtocolMessage" && params.size() == 1) {
- const std::string *protocol_message = params[0].GetIfString();
- if (!protocol_message)
- return;
- if (m_agentHost)
- m_agentHost->DispatchProtocolMessage(this, base::as_bytes(base::make_span(*protocol_message)));
- } else if (method == "loadCompleted") {
- web_contents()->GetPrimaryMainFrame()->ExecuteJavaScript(u"DevToolsAPI.setUseSoftMenu(true);",
- base::NullCallback());
- } else if (method == "loadNetworkResource" && params.size() == 3) {
- // TODO(pfeldman): handle some of the embedder messages in content.
- const std::string *url = params[0].GetIfString();
- const std::string *headers = params[1].GetIfString();
- absl::optional<int> stream_id = params[2].GetIfInt();
- if (!url || !headers || !stream_id.has_value()) {
- return;
- }
-
- GURL gurl(*url);
- if (!gurl.is_valid()) {
- base::DictionaryValue response;
- response.SetInteger("statusCode", 404);
- response.SetBoolean("urlValid", false);
- SendMessageAck(request_id, std::move(response));
- return;
- }
-
- net::NetworkTrafficAnnotationTag traffic_annotation =
- net::DefineNetworkTrafficAnnotation(
- "devtools_handle_front_end_messages", R"(
- semantics {
- sender: "Developer Tools"
- description:
- "When user opens Developer Tools, the browser may fetch "
- "additional resources from the network to enrich the debugging "
- "experience (e.g. source map resources)."
- trigger: "User opens Developer Tools to debug a web page."
- data: "Any resources requested by Developer Tools."
- destination: OTHER
- }
- policy {
- cookies_allowed: YES
- cookies_store: "user"
- setting:
- "It's not possible to disable this feature from settings."
- chrome_policy {
- DeveloperToolsAvailability {
- policy_options {mode: MANDATORY}
- DeveloperToolsAvailability: 2
- }
- }
- })");
- auto resource_request = std::make_unique<network::ResourceRequest>();
- resource_request->url = gurl;
- // TODO(caseq): this preserves behavior of URLFetcher-based implementation.
- // We really need to pass proper first party origin from the front-end.
- resource_request->site_for_cookies = net::SiteForCookies::FromUrl(gurl);
- resource_request->headers.AddHeadersFromString(*headers);
-
- mojo::Remote<network::mojom::URLLoaderFactory> file_url_loader_factory;
- scoped_refptr<network::SharedURLLoaderFactory> network_url_loader_factory;
- network::mojom::URLLoaderFactory *url_loader_factory;
- if (gurl.SchemeIsFile()) {
- file_url_loader_factory.Bind(content::CreateFileURLLoaderFactory(base::FilePath(), nullptr));
- url_loader_factory = file_url_loader_factory.get();
- } else if (content::HasWebUIScheme(gurl)) {
- base::DictionaryValue response;
- response.SetInteger("statusCode", 403);
- SendMessageAck(request_id, std::move(response));
- return;
- } else {
- auto *partition = web_contents()->GetBrowserContext()->GetStoragePartitionForUrl(gurl);
- network_url_loader_factory = partition->GetURLLoaderFactoryForBrowserProcess();
- url_loader_factory = network_url_loader_factory.get();
- }
- auto simple_url_loader = network::SimpleURLLoader::Create(
- std::move(resource_request), traffic_annotation);
- auto resource_loader = std::make_unique<NetworkResourceLoader>(
- *stream_id, request_id, this, std::move(simple_url_loader),
- url_loader_factory);
- m_loaders.insert(std::move(resource_loader));
- return;
- } else if (method == "getPreferences") {
- // Screencast is enabled by default if it's not present in the preference store.
- if (!m_prefStore->GetValue(kScreencastEnabled, NULL))
- SetPreference(kScreencastEnabled, "false");
-
- m_preferences = std::move(m_prefStore->GetValues());
- SendMessageAck(request_id, base::Value(m_preferences.Clone()));
- return;
- } else if (method == "setPreference" && params.size() >= 2) {
- const std::string *name = params[0].GetIfString();
- const std::string *value = params[1].GetIfString();
- if (!name || !value)
- return;
- SetPreference(*name, *value);
- } else if (method == "removePreference" && params.size() >= 1) {
- const std::string *name = params[0].GetIfString();
- if (!name)
- return;
- RemovePreference(*name);
- } else if (method == "clearPreferences") {
- ClearPreferences();
- } else if (method == "requestFileSystems") {
- base::ListValue fileSystemsValue;
- for (auto const &fileSystem : m_fileHelper->GetFileSystems())
- fileSystemsValue.Append(CreateFileSystemValue(fileSystem));
- CallClientFunction("DevToolsAPI", "fileSystemsLoaded", std::move(fileSystemsValue));
- } else if (method == "reattach") {
- if (!m_agentHost)
- return;
- m_agentHost->DetachClient(this);
- m_agentHost->AttachClient(this);
- } else if (method == "inspectedURLChanged" && params.size() >= 1) {
- const std::string *url = params[0].GetIfString();
- if (!url)
- return;
- const std::string kHttpPrefix = "http://";
- const std::string kHttpsPrefix = "https://";
- const std::string simplified_url =
- base::StartsWith(*url, kHttpsPrefix, base::CompareCase::SENSITIVE)
- ? url->substr(kHttpsPrefix.length())
- : base::StartsWith(*url, kHttpPrefix, base::CompareCase::SENSITIVE)
- ? url->substr(kHttpPrefix.length())
- : *url;
- // DevTools UI is not localized.
- web_contents()->UpdateTitleForEntry(web_contents()->GetController().GetActiveEntry(),
- base::UTF8ToUTF16(
- base::StringPrintf("DevTools - %s", simplified_url.c_str())));
- } else if (method == "openInNewTab" && params.size() >= 1) {
- const std::string *urlString = params[0].GetIfString();
- if (!urlString)
- return;
- GURL url(*urlString);
- if (!url.is_valid())
- return;
- content::OpenURLParams openParams(GURL(url),
- content::Referrer(),
- WindowOpenDisposition::NEW_FOREGROUND_TAB,
- ui::PAGE_TRANSITION_LINK,
- false);
- // OpenURL will (via WebContentsDelegateQt::OpenURLFromTab) call
- // application code, which may decide to close this devtools view (see
- // quicknanobrowser for example).
- //
- // Chromium always calls SendMessageAck through a callback bound to a
- // WeakPtr, we do the same here, except without the callback.
- base::WeakPtr<DevToolsFrontendQt> weakThis = m_weakFactory.GetWeakPtr();
- web_contents()->OpenURL(openParams);
- if (!weakThis)
- return;
- } else if (method == "bringToFront") {
- Activate();
- } else if (method == "closeWindow") {
- web_contents()->Close();
- } else if (method == "setEyeDropperActive" && params.size() == 1) {
- absl::optional<bool> active = params[0].GetIfBool();
- if (!active)
- return;
- SetEyeDropperActive(*active);
- } else if (method == "save" && params.size() == 3) {
- const std::string *url = params[0].GetIfString();
- const std::string *content = params[1].GetIfString();
- absl::optional<bool> saveAs = params[2].GetIfBool();
- if (!url || !content || !saveAs)
- return;
- SaveToFile(*url, *content, *saveAs);
- } else if (method == "append" && params.size() == 2) {
- const std::string *url = params[0].GetIfString();
- const std::string *content = params[1].GetIfString();
- if (!url || !content)
- return;
- AppendToFile(*url, *content);
- } else if (method == "addFileSystem" && params.size() == 1) {
- const std::string *type = params[0].GetIfString();
- if (!type)
- return;
- AddFileSystem(*type);
- } else if (method == "removeFileSystem" && params.size() == 1) {
- const std::string *fileSystemPath = params[0].GetIfString();
- if (!fileSystemPath)
- return;
- RemoveFileSystem(*fileSystemPath);
- } else if (method == "upgradeDraggedFileSystemPermissions" && params.size() == 1) {
- const std::string *fileSystemUrl = params[0].GetIfString();
- if (!fileSystemUrl)
- return;
- UpgradeDraggedFileSystemPermissions(*fileSystemUrl);
- } else {
- VLOG(1) << "Unimplemented devtools method: " << message;
- return;
- }
+ content::OpenURLParams params(GURL(url), content::Referrer(),
+ WindowOpenDisposition::NEW_FOREGROUND_TAB,
+ ui::PAGE_TRANSITION_LINK, false);
- if (request_id)
- SendMessageAck(request_id, base::Value());
+ m_inspectedContents->OpenURL(params);
}
void DevToolsFrontendQt::SetEyeDropperActive(bool active)
@@ -572,67 +184,14 @@ void DevToolsFrontendQt::SetEyeDropperActive(bool active)
return;
if (active) {
m_eyeDropper.reset(new DevToolsEyeDropper(
- m_inspectedContents,
- base::BindRepeating(&DevToolsFrontendQt::ColorPickedInEyeDropper,
- base::Unretained(this))));
+ m_inspectedContents,
+ base::BindRepeating(&DevToolsFrontendQt::ColorPickedInEyeDropper,
+ base::Unretained(this))));
} else {
m_eyeDropper.reset();
}
}
-void DevToolsFrontendQt::ColorPickedInEyeDropper(int r, int g, int b, int a)
-{
- base::DictionaryValue color;
- color.SetInteger("r", r);
- color.SetInteger("g", g);
- color.SetInteger("b", b);
- color.SetInteger("a", a);
- CallClientFunction("DevToolsAPI", "eyeDropperPickedColor", std::move(color));
-}
-
-void DevToolsFrontendQt::DispatchProtocolMessage(content::DevToolsAgentHost *agentHost, base::span<const uint8_t> message)
-{
- Q_UNUSED(agentHost);
- base::StringPiece str_message(reinterpret_cast<const char*>(message.data()), message.size());
-
- if (str_message.length() < kMaxMessageChunkSize) {
- CallClientFunction("DevToolsAPI", "dispatchMessage",
- base::Value(std::string(str_message)));
- } else {
- size_t total_size = str_message.length();
- for (size_t pos = 0; pos < str_message.length(); pos += kMaxMessageChunkSize) {
- base::StringPiece str_message_chunk = str_message.substr(pos, kMaxMessageChunkSize);
-
- CallClientFunction("DevToolsAPI", "dispatchMessageChunk",
- base::Value(std::string(str_message_chunk)),
- base::Value(base::NumberToString(pos ? 0 : total_size)));
- }
- }
-}
-
-void DevToolsFrontendQt::CallClientFunction(const std::string &object_name,
- const std::string &method_name,
- base::Value arg1, base::Value arg2, base::Value arg3,
- base::OnceCallback<void(base::Value)> cb)
-
-{
- base::Value::List arguments;
- if (!arg1.is_none()) {
- arguments.Append(std::move(arg1));
- if (!arg2.is_none()) {
- arguments.Append(std::move(arg2));
- if (!arg3.is_none()) {
- arguments.Append(std::move(arg3));
- }
- }
- }
- web_contents()->GetPrimaryMainFrame()->ExecuteJavaScriptMethod(base::ASCIIToUTF16(object_name),
- base::ASCIIToUTF16(method_name),
- std::move(arguments),
- std::move(cb));
-
-}
-
// static
bool DevToolsFrontendQt::IsValidFrontendURL(const GURL &url)
{
@@ -642,117 +201,21 @@ bool DevToolsFrontendQt::IsValidFrontendURL(const GURL &url)
return url.spec() == GetFrontendURL();
}
-void DevToolsFrontendQt::SendMessageAck(int request_id, base::Value arg)
-{
- base::Value id_value(request_id);
- CallClientFunction("DevToolsAPI", "embedderMessageAck", std::move(id_value), std::move(arg));
-}
-
-void DevToolsFrontendQt::AgentHostClosed(content::DevToolsAgentHost *agentHost)
+void DevToolsFrontendQt::InspectedContentsClosing()
{
- DCHECK(agentHost == m_agentHost.get());
- m_agentHost = nullptr;
+ // Called for already destroyed guest views
m_inspectedContents = nullptr;
- m_inspectedAdapter = nullptr;
- Close();
-}
-
-void DevToolsFrontendQt::SaveToFile(const std::string &url, const std::string &content, bool saveAs)
-{
- m_fileHelper->Save(
- url, content, saveAs,
- base::BindOnce(&DevToolsFrontendQt::FileSavedAs, m_weakFactory.GetWeakPtr(), url),
- base::BindOnce(&DevToolsFrontendQt::CanceledFileSaveAs, m_weakFactory.GetWeakPtr(),
- url));
-}
-
-void DevToolsFrontendQt::FileSavedAs(const std::string &url, const std::string &fileSystemPath)
-{
- CallClientFunction("DevToolsAPI", "savedURL", base::Value(url), base::Value(fileSystemPath));
+ web_contents()->ClosePage();
}
-void DevToolsFrontendQt::CanceledFileSaveAs(const std::string &url)
+std::string DevToolsFrontendQt::GetId(content::WebContents *inspectedContents)
{
- CallClientFunction("DevToolsAPI", "canceledSaveURL", base::Value(url));
+ return content::DevToolsAgentHost::GetOrCreateFor(inspectedContents)->GetId();
}
-void DevToolsFrontendQt::AppendToFile(const std::string &url, const std::string &content)
+void DevToolsFrontendQt::CloseWindow()
{
- m_fileHelper->Append(
- url, content,
- base::BindOnce(&DevToolsFrontendQt::AppendedTo, m_weakFactory.GetWeakPtr(), url));
-}
-
-void DevToolsFrontendQt::AppendedTo(const std::string &url)
-{
- CallClientFunction("DevToolsAPI", "appendedToURL", base::Value(url));
-}
-
-void DevToolsFrontendQt::AddFileSystem(const std::string &type)
-{
- CHECK(IsValidFrontendURL(web_contents()->GetLastCommittedURL()) && m_frontendHost);
- m_fileHelper->AddFileSystem(type, base::NullCallback());
-}
-
-void DevToolsFrontendQt::UpgradeDraggedFileSystemPermissions(const std::string &fileSystemUrl)
-{
- CHECK(IsValidFrontendURL(web_contents()->GetLastCommittedURL()) && m_frontendHost);
- m_fileHelper->UpgradeDraggedFileSystemPermissions(fileSystemUrl, base::NullCallback());
-}
-
-void DevToolsFrontendQt::RemoveFileSystem(const std::string &fileSystemPath)
-{
- CHECK(IsValidFrontendURL(web_contents()->GetLastCommittedURL()) && m_frontendHost);
- m_fileHelper->RemoveFileSystem(fileSystemPath);
-}
-
-// DevToolsFileHelper::Delegate implementation
-// based on chrome/browser/devtools/devtools_ui_bindings.cc
-void DevToolsFrontendQt::FileSystemAdded(const std::string &error,
- const DevToolsFileHelper::FileSystem *file_system)
-{
- if (file_system) {
- CallClientFunction("DevToolsAPI", "fileSystemAdded", base::Value(error),
- CreateFileSystemValue(*file_system));
- } else {
- CallClientFunction("DevToolsAPI", "fileSystemAdded", base::Value(error));
- }
-}
-
-void DevToolsFrontendQt::FileSystemRemoved(const std::string &file_system_path)
-{
- CallClientFunction("DevToolsAPI", "fileSystemRemoved", base::Value(file_system_path));
-}
-
-void DevToolsFrontendQt::FilePathsChanged(const std::vector<std::string> &changed_paths,
- const std::vector<std::string> &added_paths,
- const std::vector<std::string> &removed_paths)
-{
- const int kMaxPathsPerMessage = 1000;
- size_t changed_index = 0;
- size_t added_index = 0;
- size_t removed_index = 0;
- // Dispatch limited amount of file paths in a time to avoid
- // IPC max message size limit. See https://crbug.com/797817.
- while (changed_index < changed_paths.size() || added_index < added_paths.size()
- || removed_index < removed_paths.size()) {
- int budget = kMaxPathsPerMessage;
- base::ListValue changed, added, removed;
- while (budget > 0 && changed_index < changed_paths.size()) {
- changed.Append(changed_paths[changed_index++]);
- --budget;
- }
- while (budget > 0 && added_index < added_paths.size()) {
- added.Append(added_paths[added_index++]);
- --budget;
- }
- while (budget > 0 && removed_index < removed_paths.size()) {
- removed.Append(removed_paths[removed_index++]);
- --budget;
- }
- CallClientFunction("DevToolsAPI", "fileSystemFilesChangedAddedRemoved", std::move(changed),
- std::move(added), std::move(removed));
- }
+ web_contents()->Close();
}
} // namespace QtWebEngineCore
diff --git a/src/core/devtools_frontend_qt.h b/src/core/devtools_frontend_qt.h
index 5c1237bbc..b867d4af1 100644
--- a/src/core/devtools_frontend_qt.h
+++ b/src/core/devtools_frontend_qt.h
@@ -11,31 +11,24 @@
#include "base/containers/unique_ptr_adapters.h"
#include "base/memory/weak_ptr.h"
-#include "chrome/browser/devtools/devtools_file_helper.h"
-#include "content/public/browser/devtools_agent_host.h"
+#include "chrome/browser/devtools/devtools_ui_bindings.h"
#include "content/public/browser/web_contents_observer.h"
-namespace base {
-class Value;
-}
+class DevToolsEyeDropper;
namespace content {
-class DevToolsFrontendHost;
-class NavigationHandle;
+class DevToolsAgentHost;
class WebContents;
-} // namespace content
-
-class DevToolsEyeDropper;
-class PersistentPrefStore;
+} // namespace content
namespace QtWebEngineCore {
+class WebContentsAdapter;
-class DevToolsFrontendQt : public content::WebContentsObserver,
- public content::DevToolsAgentHostClient,
- public DevToolsFileHelper::Delegate
+class DevToolsFrontendQt : public DevToolsUIBindings::Delegate, public content::WebContentsObserver
{
public:
- static DevToolsFrontendQt *Show(QSharedPointer<WebContentsAdapter> frontendAdapter, content::WebContents *inspectedContents);
+ static DevToolsFrontendQt *Show(QSharedPointer<WebContentsAdapter> frontendAdapter,
+ content::WebContents *inspectedContents);
void Activate();
void Focus();
@@ -44,82 +37,50 @@ public:
void DisconnectFromTarget();
- void CallClientFunction(const std::string &object_name,
- const std::string &method_name,
- base::Value arg1 = {},
- base::Value arg2 = {},
- base::Value arg3 = {},
- base::OnceCallback<void(base::Value)> cb = base::NullCallback());
-
- WebContentsDelegateQt *frontendDelegate() const
- {
- return m_frontendDelegate;
- }
+ WebContentsDelegateQt *frontendDelegate() const;
static bool IsValidFrontendURL(const GURL &url);
+ static std::string GetId(content::WebContents *inspectedContents);
protected:
- DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webContentsAdapter, content::WebContents *inspectedContents);
+ DevToolsFrontendQt(QSharedPointer<WebContentsAdapter> webContentsAdapter,
+ content::WebContents *inspectedContents);
~DevToolsFrontendQt() override;
- // content::DevToolsAgentHostClient implementation.
- void AgentHostClosed(content::DevToolsAgentHost* agent_host) override;
- void DispatchProtocolMessage(content::DevToolsAgentHost* agent_host, base::span<const uint8_t> message) override;
-
- void SetPreferences(const std::string& json);
- void HandleMessageFromDevToolsFrontend(base::Value::Dict message);
-
private:
- // WebContentsObserver overrides
- void ReadyToCommitNavigation(content::NavigationHandle* navigation_handle) override;
- void DocumentOnLoadCompletedInPrimaryMainFrame() override;
- void WebContentsDestroyed() override;
-
- // DevToolsFileHelper::Delegate overrides.
- void FileSystemAdded(const std::string &error,
- const DevToolsFileHelper::FileSystem *file_system) override;
- void FileSystemRemoved(const std::string &file_system_path) override;
- void FilePathsChanged(const std::vector<std::string> &changed_paths,
- const std::vector<std::string> &added_paths,
- const std::vector<std::string> &removed_paths) override;
-
- void SendMessageAck(int request_id, base::Value arg1);
- void SetPreference(const std::string &name, const std::string &value);
- void RemovePreference(const std::string &name);
- void ClearPreferences();
- void CreateJsonPreferences(bool clear);
- void SetEyeDropperActive(bool active);
void ColorPickedInEyeDropper(int r, int g, int b, int a);
- void SaveToFile(const std::string &url, const std::string &content, bool saveAs);
- void FileSavedAs(const std::string &url, const std::string &fileSystemPath);
- void CanceledFileSaveAs(const std::string &url);
- void AppendToFile(const std::string &url, const std::string &content);
- void AppendedTo(const std::string &url);
- void AddFileSystem(const std::string &type);
- void UpgradeDraggedFileSystemPermissions(const std::string &fileSystem);
- void RemoveFileSystem(const std::string &fileSystemPath);
+ // content::WebContentsObserver overrides
+ void WebContentsDestroyed() override;
+
+ // DevToolsUIBindings::Delegate overrides
+ void ActivateWindow() override;
+ void SetEyeDropperActive(bool active) override;
+ void OpenInNewTab(const std::string &url) override;
+ void InspectedContentsClosing() override;
+ void OnLoadCompleted() override;
+
+ void InspectElementCompleted() override{};
+ void CloseWindow() override;
+ void Inspect(scoped_refptr<content::DevToolsAgentHost>) override{};
+ void SetInspectedPageBounds(const gfx::Rect &) override{};
+ void SetIsDocked(bool) override{};
+ void SetWhitelistedShortcuts(const std::string &) override{};
+ void OpenNodeFrontend() override{};
+ void ReadyForTest() override{};
+ void ConnectionReady() override{};
+ void SetOpenNewWindowForPopups(bool) override{};
+ void RenderProcessGone(bool) override{};
+ void ShowCertificateViewer(const std::string &) override{};
// We shouldn't be keeping it alive
QWeakPointer<WebContentsAdapter> m_frontendAdapter;
- WebContentsAdapter *m_inspectedAdapter;
- WebContentsDelegateQt *m_frontendDelegate;
content::WebContents *m_inspectedContents;
- scoped_refptr<content::DevToolsAgentHost> m_agentHost;
- int m_inspect_element_at_x;
- int m_inspect_element_at_y;
- std::unique_ptr<content::DevToolsFrontendHost> m_frontendHost;
+ content::WebContents *m_outermostContents;
std::unique_ptr<DevToolsEyeDropper> m_eyeDropper;
- std::unique_ptr<DevToolsFileHelper> m_fileHelper;
-
- class NetworkResourceLoader;
- std::set<std::unique_ptr<NetworkResourceLoader>, base::UniquePtrComparator> m_loaders;
-
- base::Value::Dict m_preferences;
- scoped_refptr<PersistentPrefStore> m_prefStore;
- base::WeakPtrFactory<DevToolsFrontendQt> m_weakFactory;
+ DevToolsUIBindings *m_bindings;
};
} // namespace QtWebEngineCore
-#endif // DEVTOOLS_FRONTEND_QT_H
+#endif // DEVTOOLS_FRONTEND_QT_H
diff --git a/src/core/doc/about_credits_entry.tmpl b/src/core/doc/about_credits_entry.tmpl
index 2bb9cff4e..aa94f2945 100644
--- a/src/core/doc/about_credits_entry.tmpl
+++ b/src/core/doc/about_credits_entry.tmpl
@@ -1,5 +1,6 @@
/*!
-\page qtwebengine-3rdparty-{{name-sanitized}}.html attribution
+\page qtwebengine-3rdparty-{{name-sanitized}}.html
+\attribution
\ingroup qtwebengine-licensing
\brief {{license-type}}
\title {{name}}
diff --git a/src/core/doc/qtwebengine.qdocconf b/src/core/doc/qtwebengine.qdocconf
index 5cbe9e500..6b78f13f8 100644
--- a/src/core/doc/qtwebengine.qdocconf
+++ b/src/core/doc/qtwebengine.qdocconf
@@ -31,7 +31,8 @@ qhp.QtWebEngine.subprojects.examples.selectors = doc:example
qhp.QtWebEngine.subprojects.examples.sortPages = true
manifestmeta.highlighted.names += "QtWebEngine/WebEngine Widgets Simple Browser Example" \
- "QtWebEngine/WebEngine Quick Nano Browser"
+ "QtWebEngine/WebEngine Quick Nano Browser" \
+ "QtWebEngine/Recipe Browser"
tagfile = ../../../doc/qtwebengine/qtwebengine.tags
@@ -91,5 +92,5 @@ navigation.qmltypespage = "Qt WebEngine QML Types"
# \QWE macro expands to 'Qt WebEngine' without auto-linking anywhere.
macro.QWE = "Qt \\WebEngine"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/core/doc/snippets/qtwebengine_qwebenginepage_snippet.cpp b/src/core/doc/snippets/qtwebengine_qwebenginepage_snippet.cpp
index 309ad8233..6b39eed03 100644
--- a/src/core/doc/snippets/qtwebengine_qwebenginepage_snippet.cpp
+++ b/src/core/doc/snippets/qtwebengine_qwebenginepage_snippet.cpp
@@ -1,12 +1,12 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
void wrapInFunction()
{
//! [0]
- m_view->page()->findText(QStringLiteral("Qt"), QWebEnginePage::FindFlags(), [this](bool found) {
- if (!found) QMessageBox::information(m_view, QString(), QStringLiteral("No occurrences found"));
+ m_view->page()->findText(QStringLiteral("Qt"), QWebEnginePage::FindFlags(), [this](const QWebEngineFindTextResult &result) {
+ if (result.numberOfMatches() == 0) QMessageBox::information(m_view, QString(), QStringLiteral("No occurrences found"));
});
//! [0]
diff --git a/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc b/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc
index ee22ea774..9a7370d62 100644
--- a/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc
+++ b/src/core/doc/snippets/qtwebenginecore_build_snippet.qdoc
@@ -7,5 +7,5 @@ QT += webenginecore
//! [2]
find_package(Qt6 REQUIRED COMPONENTS WebEngineCore)
-target_link_libraries(target PRIVATE Qt::WebEngineCore)
+target_link_libraries(target PRIVATE Qt6::WebEngineCore)
//! [2]
diff --git a/src/core/doc/src/qtwebengine-debugging.qdoc b/src/core/doc/src/qtwebengine-debugging.qdoc
index 3bb6a7029..3dd4d9276 100644
--- a/src/core/doc/src/qtwebengine-debugging.qdoc
+++ b/src/core/doc/src/qtwebengine-debugging.qdoc
@@ -49,6 +49,12 @@
interface on, so that you can access the developer tools from a remote
device.
+ To avoid WebSocket errors during remote debugging, add an additional command-line
+ argument \c {--remote-allow-origins=<origin>[,<origin>, ...]}, where \c <origin> refers to the request origin.
+ Use \c {--remote-allow-origins=*} to allow connections from all origins. If nothing is specified,
+ \QWE will add \c {--remote-allow-origins=*} to command-line arguments when remote-debugging is enabled,
+ thereby allowing requests from all origins.
+
For a detailed explanation of the capabilities of developer tools, see the
\l {Chrome DevTools} page.
diff --git a/src/core/doc/src/qtwebengine-deploying.qdoc b/src/core/doc/src/qtwebengine-deploying.qdoc
index 3fb46a672..3d8a976c8 100644
--- a/src/core/doc/src/qtwebengine-deploying.qdoc
+++ b/src/core/doc/src/qtwebengine-deploying.qdoc
@@ -4,6 +4,7 @@
/*!
\page qtwebengine-deploying.html
\title Deploying Qt WebEngine Applications
+ \ingroup explanations-webtechnologies
The way to package and deploy applications varies between operating systems.
For Windows and \macos, \l{The Windows Deployment Tool}{windeployqt} and
@@ -97,6 +98,12 @@
\li \c icudtl.dat provides support for International Components for
Unicode (ICU). It is the Chromium version of ICU, which is not
needed if \QWE was configured to use the system ICU.
+ \li \c v8_context_snapshot.bin contains a previously prepared snapshot
+ of a v8 context used to speed up initialization. Debug builds use
+ separate snapshots with the file name extension \c .debug.bin instead
+ of \c .bin. On \macos, there is a snapshot for each architecture named
+ accordingly, for example \c v8_context_snapshot.arm64.bin or
+ \c v8_context_snapshot.arm64.debug.bin.
\endlist
Resources are searched from the following locations:
@@ -138,4 +145,55 @@
QTQUICK_COMPILER_SKIPPED_RESOURCES += resources/my_resource.qrc
\endcode
+ \section2 \macos Specific Deployment Steps
+
+ To deploy a \QWE application on \macos, you will need to ensure that the \QWE process is signed
+ with an entitlements file that at least contains the entitlements listed in
+ QtWebEngineCore.framework/Helpers/QtWebEngineProcess.app/Contents/Resources/QtWebEngineProcess.entitlements.
+
+ To deploy a \QWE application that accesses the microphone or camera
+ on \macos, you will need to provide texts for the messages that will be shown to the user to
+ explain why the application asks for permission to access to the camera or microphone.
+ To do this, add the texts to the application's \c Info.plist file using the keys
+ described below.
+
+ For the camera usage message, provide a text using the following key:
+ \code
+ <key>NSCameraUsageDescription</key>
+ <string>Your message text for camera usage.</string>
+ \endcode
+
+ See also \l{https://developer.apple.com/documentation/bundleresources/information_property_list/nscamerausagedescription}
+ {Apple's property list file documentation}.
+
+ For the microphone usage message, provide a text using the following key:
+ \code
+ <key>NSMicrophoneUsageDescription</key>
+ <string>Your message text for microphone usage.</string>
+ \endcode
+
+ See also \l{https://developer.apple.com/documentation/bundleresources/information_property_list/nsmicrophoneusagedescription}
+ {Apple's property list file documentation}.
+
+ To notarize an application that accesses the camera or the microphone,
+ you will need to add the corresponding keys to your application's entitlements file used for
+ deployment and notarization.
+
+ To enable access to the camera, add:
+ \code
+ <key>com.apple.security.device.camera</key>
+ <true/>
+ \endcode
+
+ See also \l{https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_device_camera}
+ {Apple's camera entitlement documentation}.
+
+ To enable access to the microphone, add:
+ \code
+ <key>com.apple.security.device.microphone</key>
+ <true/>
+ \endcode
+
+ See also \l{https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_security_device_microphone}
+ {Apple's microphone entitlement documentation}.
*/
diff --git a/src/core/doc/src/qtwebengine-features.qdoc b/src/core/doc/src/qtwebengine-features.qdoc
index a564641a5..9465d75a2 100644
--- a/src/core/doc/src/qtwebengine-features.qdoc
+++ b/src/core/doc/src/qtwebengine-features.qdoc
@@ -4,6 +4,7 @@
/*!
\page qtwebengine-features.html
\title Qt WebEngine Features
+ \ingroup explanations-webtechnologies
\brief Summarizes \QWE features.
@@ -11,6 +12,7 @@
\list
\li \l{Audio and Video Codecs}
+ \li \l{WebEngineDriver}
\li \l{Chromium DevTools}
\li \l{Client Certificates}
\li \l{Custom Schemes}
@@ -24,7 +26,6 @@
\li \l{HTTP/2 Protocol}
\li \l{Local Storage}
\li \l{Native Dialogs}
- \li \l{Pepper Plugin API}
\li \l{PDF File Viewing}
\li \l{Page Lifecycle API}
\li \l{Print to PDF}
@@ -75,6 +76,68 @@
codecs, open source implementations, such as \l{OpenH264 Project Homepage}
{OpenH264}, are available.
+ \section1 WebEngineDriver
+
+ With WebEngineDriver, you can automate the testing of web sites across browsers.
+ WebEngineDriver is based on ChromeDriver and can be used the same way.
+ For more information about ChromeDriver and its use, visit
+ \l {https://chromedriver.chromium.org/}{ChromeDriver user site}.
+
+ WebEngineDriver has slight modifications compared to ChromeDriver to be able to connect to
+ \QWE based browsers. It is compatible with \QWE example browsers, such as
+ \l {WebEngine Widgets Simple Browser Example}{Simple Browser} or
+ \l{WebEngine Quick Nano Browser}{Nano Browser}.
+
+ The browser automation is scripted through a WebDriver client like the
+ \l {https://www.selenium.dev/}{Selenium WebDriver}.
+ For example, WebEngineDriver can be used with the Python lanugage bindings of
+ Selenium WebDriver:
+
+ \code
+ from selenium import webdriver
+ from selenium.webdriver.chrome.service import Service
+
+ service = Service(executable_path='QTDIR/libexec/webenginedriver')
+ options = webdriver.ChromeOptions()
+ options.binary_location = 'path/to/browser_binary'
+
+ driver = webdriver.Chrome(service=service, options=options)
+ driver.get("http://www.google.com/")
+ driver.quit()
+ \endcode
+
+ In this example,
+ \list
+ \li \c executable_path has to be set to the WebEngineDriver's binary path
+ \li \c QTDIR is the directory where Qt is installed
+ \li \c options.binary_location has to be set to the browser's binary path
+ \endlist
+
+ \note On Windows: \c executable_path='QTDIR/bin/webenginedriver.exe'
+
+ Before executing the script, the \c QTWEBENGINE_REMOTE_DEBUGGING environment variable has to
+ be set. Its value is a port number what is used by both the browser and WebEngineDriver to
+ communicate with each other.
+ \badcode
+ export QTWEBENGINE_REMOTE_DEBUGGING=12345
+ \endcode
+
+ By executing, the script opens the specified web browser and loads the Google web site.
+
+ WebEngineDriver can be also attached to an already running browser if it was started with the
+ remote debugging port set. \c options.debugger_address has to be set to the remote debugging
+ address in the script:
+
+ \code
+ options.debugger_address = 'localhost:12345'
+ \endcode
+
+ In this case, \c options.binary_location should not be set because the browser is already
+ running. The environment variable \c QTWEBENGINE_REMOTE_DEBUGGING is not used by the
+ WebEngineDriver if \c options.debugger_address is set.
+
+ \note WebEngineDriver must be built with the same version of Chromium as \QWE is using.
+
\section1 Chromium DevTools
The Chromium DevTools provide the ability to inspect and debug layout and
@@ -82,7 +145,7 @@
This feature can be tested by launching a \QWE application with the
command line option \c {--remote-debugging-port=[your-port]} or by setting
- the environment variable \c QTWEBENGINE_REMOTE_DEBUGGING, and then using a
+ the environment variable \c QTWEBENGINE_REMOTE_DEBUGGING and then using a
Chromium based browser (such as \l{WebEngine Widgets Simple Browser Example}
{Simple Browser} or \l{WebEngine Quick Nano Browser}{Nano Browser}) to connect
to \c {http://localhost:[your-port]}.
@@ -95,6 +158,12 @@
--webEngineArgs --remote-debugging-port=5000
\endcode
+ To avoid WebSocket errors during remote debugging, add an additional command-line argument
+ \c {--remote-allow-origins=<origin>[,<origin>, ...]}, where \c <origin> refers to the request origin.
+ Use \c {--remote-allow-origins=*} to allow connections from all origins. If nothing is specified,
+ \QWE will add \c {--remote-allow-origins=*} to command-line arguments when remote-debugging is enabled,
+ thereby allowing requests from all origins.
+
The Chromium DevTools page can also be shown within the application. To set
this up, you can call either QWebEnginePage::setInspectedPage() to the page
to be inspected, which implicitly loads the DevTools into the \c this page,
@@ -298,6 +367,12 @@
tested by using \l{WebEngine Widgets Maps Example}{Maps} and allowing it to
find the current position of the user.
+ \note On Windows 11, enable settings to grant the maps example access to
+ Windows location services. In the Settings App under
+ \uicontrol {Privacy & Security} > \uicontrol {Location}, enable \uicontrol
+ {Location services}, \uicontrol {Let apps access your location} and \uicontrol
+ {Let desktop apps access your location}.
+
See \l{Qt Positioning} for a possible backend setup like the GPS or IP based positioning.
Support for this feature was added in Qt 5.5.0.
@@ -383,33 +458,6 @@
WebEngineView::colorDialogRequested(),
WebEngineView::fileDialogRequested(), and
WebEngineView::formValidationMessageRequested() signals. For an example,
- see \l{WebEngine Qt Quick Custom Dialogs Example}.
-
- \section1 Pepper Plugin API
-
- \QWE supports loading Pepper Plugin API (PPAPI) plugins if
- WebEngineSettings::pluginsEnabled or QWebEngineSettings::PluginsEnabled
- is set.
-
- The plugins must be loaded manually using the Chromium command line syntax with the
- \c --register-pepper-plugins argument. The argument value is a list of
- entries, separated by commas, that contain the file path and one or several
- MIME types, separated by semicolons:
-
- \badcode
- <file-path-plugin1>;<mime-type-plugin1>,<file-path-plugin2>;<mime-type1-plugin2>;<mime-type2-plugin2>
- \endcode
-
- For example:
-
- \badcode
- --webEngineArgs --register-pepper-plugins="libppapi_example.so;application/x-ppapi-example"
- \endcode
-
- The MIME type is important because it determines which embeds the plugin is
- used for.
-
- Support for this feature was added in Qt 5.6.0.
\section1 PDF File Viewing
diff --git a/src/core/doc/src/qtwebengine-global.qdoc b/src/core/doc/src/qtwebengine-global.qdoc
index 57df8b3ac..7f6636c16 100644
--- a/src/core/doc/src/qtwebengine-global.qdoc
+++ b/src/core/doc/src/qtwebengine-global.qdoc
@@ -40,3 +40,17 @@
Returns the version number of last Chromium version security patches have been
merged from.
*/
+
+/*!
+ \fn QString qWebEngineGetDomainAndRegistry(const QUrl &url)
+ \relates <qtwebenginecoreglobal.h>
+ \since 6.6
+
+ Returns the domain of the host, that is, the effective top-level domain
+ (eTLD) and the first domain below it, from \a url.
+
+ This function supports internationalized domain names (IDN). In this case,
+ it returns the domain encoded in Punycode.
+
+ If the host is not a domain, returns an empty string.
+*/
diff --git a/src/core/doc/src/qtwebengine-overview.qdoc b/src/core/doc/src/qtwebengine-overview.qdoc
index 193116b3e..6eccc669e 100644
--- a/src/core/doc/src/qtwebengine-overview.qdoc
+++ b/src/core/doc/src/qtwebengine-overview.qdoc
@@ -4,6 +4,7 @@
/*!
\page qtwebengine-overview.html
\title Qt WebEngine Overview
+ \ingroup explanations-webtechnologies
The \QWE module provides a web browser engine that makes it easy to embed content from
the World Wide Web into your Qt application on platforms that do not have a native web engine.
@@ -162,7 +163,7 @@
The following sample QML application loads a web page using the \l{WebEngineView::}{url}
property:
- \quotefromfile webenginequick/minimal/main.qml
+ \quotefromfile minimal/main.qml
\skipto import
\printuntil /^\}/
@@ -216,7 +217,7 @@
open SSL connections. Instead, \QWE uses the root CA certificates from the operating
system to validate the peer's certificate.
- The \l{WebEngineCertificateError::error} and \l{QWebEngineCertificateError::Type} enumerations
+ The \l{WebEngineCertificateError::type} and \l{QWebEngineCertificateError::Type} enumerations
provide information about the types of certificate errors that might occur. The errors can be
handled by using the WebEngineView::certificateError QML method or by connecting to the
QWebEnginePage::certificateError signal.
diff --git a/src/core/doc/src/qtwebengine-platform-notes.qdoc b/src/core/doc/src/qtwebengine-platform-notes.qdoc
index 76f5bbfda..33bac101a 100644
--- a/src/core/doc/src/qtwebengine-platform-notes.qdoc
+++ b/src/core/doc/src/qtwebengine-platform-notes.qdoc
@@ -34,11 +34,12 @@
On all platforms, the following tools are required at build time:
\list
+ \li C++20 compiler support
\li CMake 3.19 or newer
\li \l Python 3 with html5lib library
\li Bison, Flex
\li GPerf
- \li Node.js version 12 or later
+ \li Node.js version 14 or later
\endlist
\section2 Windows
@@ -49,16 +50,10 @@
\li Visual Studio 2019 or later, or clang-cl version 10 or later
\li Active Template Library (ATL), usually included in the Visual Studio
installation
- \li Windows 10 SDK version 10.0.20348.0 or later
+ \li Windows 11 SDK version 10.0.22621.0 or later
\endlist
- \QWE can only be built on 64-bit Windows, with a x64-bit toolchain.
- For building \QWE for x86 applications, you need to configure
- and compile Qt with the Visual Studio x64 to x86 cross-compile
- toolchain. This toolchain can be set up on the command line by running
- \c{vcvarsall.bat amd64_x86}.
-
- \note It is not recommended to use tools form \c msys2 or \c cygwin to build \QWE as it may result in build errors.
+ \note It is not recommended to use tools from \c msys2 or \c cygwin to build \QWE as it may result in build errors.
\section2 Linux
@@ -193,16 +188,36 @@
or VoiceOver on \macos.
\endlist
- Due to some limitations, the Linux QPA plugin almost always reports that accessibility should
- be activated. On big HTML pages, this can cause a significant slowdown in rendering speed.
+ On some old Linux configurations, accessibility can cause a significant slowdown
+ on large HTML pages.
- Because of that, \QWE accessibility support is disabled by default
- on Linux.
- It can be re-enabled by setting the \c QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment
- variable to a non-empty value.
+ Because of that, \QWE accessibility support can be disabled on Linux, by setting the
+ \c QTWEBENGINE_ENABLE_LINUX_ACCESSIBILITY environment variable to 0.
\section1 Popups in Fullscreen Applications on Windows
Because of a limitation in the Windows compositor, applications that show a fullscreen web
engine view will not properly display popups or other top-level windows. The reason and
workaround is described in \l {Fullscreen OpenGL Based Windows}.
+
+ \target windows_manifest
+ \section1 Windows Application Manifest
+ A manifest is an XML file that is read when the program starts and informs Windows how to run the program.
+ Some \QWE features may require adding a manifest file for the user application to work correctly on Windows.
+
+ The following snippets show the manifest file's structure and how to embed it into the program.
+
+ \note These code snippets are taken from the \l {WebEngine Quick Nano Browser} example.
+
+ The manifest file defines which Windows versions the application supports.
+ \l {QWebEngineProfile::} {httpUserAgent} needs this information to report the correct Windows version.
+ \quotefile ../../../../examples/webenginequick/quicknanobrowser/quicknanobrowser.exe.manifest
+
+ To embed the file into the executable, add it to the sources:
+ \quotefromfile ../../../../examples/webenginequick/quicknanobrowser/CMakeLists.txt
+ \skipto qt_add_executable
+ \dots
+ \printuntil endif
+ \dots
+
+ For more information, see the \l {https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests} {Application manifest documentation page}.
*/
diff --git a/src/core/doc/src/qwebengine-licensing.qdoc b/src/core/doc/src/qwebengine-licensing.qdoc
index 2b1bd2845..796a9664d 100644
--- a/src/core/doc/src/qwebengine-licensing.qdoc
+++ b/src/core/doc/src/qwebengine-licensing.qdoc
@@ -14,11 +14,16 @@ respect the licenses of Chromium, and third-party code included in
Chromium. The arguably most restrictive license to be respected by
all users is LGPLv2.1.
+\note Any GPL licenses listed below are only used to access Linux system
+resources. \QWE does not link to nor distribute GPL binary code, and
+it does not affect users of \QWE.
+
Third party licenses included in the sources are:
*/
/*!
-\page qtwebengine-3rdparty-chromium-global.html attribution
+\page qtwebengine-3rdparty-chromium-global.html
+\attribution
\ingroup qtwebengine-licensing
\title Chromium License
\brief BSD
diff --git a/src/core/doc/src/qwebenginepage_lgpl.qdoc b/src/core/doc/src/qwebenginepage_lgpl.qdoc
index 19efa2903..c2515cd13 100644
--- a/src/core/doc/src/qwebenginepage_lgpl.qdoc
+++ b/src/core/doc/src/qwebenginepage_lgpl.qdoc
@@ -115,85 +115,86 @@
should be enabled to get automatic focus.
\value PasteAndMatchStyle Paste content from the clipboard with current style.
- \value OpenLinkInThisWindow Open the current link in the current window. (Added in Qt 5.6)
- \value OpenLinkInNewWindow Open the current link in a new window. Requires implementation of
- \l createWindow() or \l newWindowRequested() (Added in Qt 5.6)
- \value OpenLinkInNewTab Open the current link in a new tab. Requires implementation of
- \l createWindow() or \l newWindowRequested(). (Added in Qt 5.6)
- \value OpenLinkInNewBackgroundTab Open the current link in a new background tab. Requires
- implementation of \l createWindow() or \l newWindowRequested(). (Added in Qt 5.7)
- \value CopyLinkToClipboard Copy the current link to the clipboard. (Added in Qt 5.6)
-
- \value CopyImageToClipboard Copy the clicked image to the clipboard. (Added in Qt 5.6)
- \value CopyImageUrlToClipboard Copy the clicked image's URL to the clipboard. (Added in Qt 5.6)
- \value CopyMediaUrlToClipboard Copy the hovered audio or video's URL to the clipboard. (Added in Qt 5.6)
- \value ToggleMediaControls Toggle between showing and hiding the controls for the hovered audio
- or video element. (Added in Qt 5.6)
- \value ToggleMediaLoop Toggle whether the hovered audio or video should loop on completetion or
- not. (Added in Qt 5.6)
- \value ToggleMediaPlayPause Toggle the play/pause state of the hovered audio or video element.
- (Added in Qt 5.6)
- \value ToggleMediaMute Mute or unmute the hovered audio or video element. (Added in Qt 5.6)
- \value DownloadLinkToDisk Download the current link to the disk. Requires a slot for
- \l{QWebEngineProfile::}{downloadRequested()}. (Added in Qt 5.6)
- \value DownloadImageToDisk Download the highlighted image to the disk. Requires a slot for
- \l{QWebEngineProfile::}{downloadRequested()}. (Added in Qt 5.6)
- \value DownloadMediaToDisk Download the hovered audio or video to the disk. Requires a slot for
- \l{QWebEngineProfile::}{downloadRequested()}. (Added in Qt 5.6)
-
- \value InspectElement Trigger any attached Web Inspector to inspect the highlighed element.
- (Added in Qt 5.6)
- \value ExitFullScreen Exit the fullscreen mode. (Added in Qt 5.6)
- \value RequestClose Request to close the web page. If defined, the \c{window.onbeforeunload}
+ \value [since 5.6] OpenLinkInThisWindow Open the current link in the current window.
+ \value [since 5.6] OpenLinkInNewWindow Open the current link in a new window. Requires implementation of
+ \l createWindow() or \l newWindowRequested().
+ \value [since 5.6] OpenLinkInNewTab Open the current link in a new tab. Requires implementation of
+ \l createWindow() or \l newWindowRequested().
+ \value [since 5.7] OpenLinkInNewBackgroundTab Open the current link in a new background tab. Requires
+ implementation of \l createWindow() or \l newWindowRequested().
+ \value [since 5.6] CopyLinkToClipboard Copy the current link to the clipboard.
+
+ \value [since 5.6] CopyImageToClipboard Copy the clicked image to the clipboard.
+ \value [since 5.6] CopyImageUrlToClipboard Copy the clicked image's URL to the clipboard.
+ \value [since 5.6] CopyMediaUrlToClipboard Copy the hovered audio or video's URL to the clipboard.
+ \value [since 5.6] ToggleMediaControls Toggle between showing and hiding the controls for the hovered audio
+ or video element.
+ \value [since 5.6] ToggleMediaLoop Toggle whether the hovered audio or video should loop on completetion or
+ not.
+ \value [since 5.6] ToggleMediaPlayPause Toggle the play/pause state of the hovered audio or video element.
+ \value [since 5.6] ToggleMediaMute Mute or unmute the hovered audio or video element.
+ \value [since 5.6] DownloadLinkToDisk Download the current link to the disk. Requires a slot for
+ \l{QWebEngineProfile::}{downloadRequested()}.
+ \value [since 5.6] DownloadImageToDisk Download the highlighted image to the disk. Requires a slot for
+ \l{QWebEngineProfile::}{downloadRequested()}.
+ \value [since 5.6] DownloadMediaToDisk Download the hovered audio or video to the disk. Requires a slot for
+ \l{QWebEngineProfile::}{downloadRequested()}.
+
+ \value [since 5.6] InspectElement Trigger any attached Web Inspector to inspect the highlighed element.
+ \value [since 5.6] ExitFullScreen Exit the fullscreen mode.
+ \value [since 5.6] RequestClose Request to close the web page. If defined, the \c{window.onbeforeunload}
handler is run, and the user can confirm or reject to close the page. If the close
- request is confirmed, \c windowCloseRequested is emitted. (Added in Qt 5.6)
- \value Unselect Clear the current selection. (Added in Qt 5.7)
- \value SavePage Save the current page to disk. MHTML is the default format that is used to store
+ request is confirmed, \c windowCloseRequested is emitted.
+ \value [since 5.7] Unselect Clear the current selection.
+ \value [since 5.7] SavePage Save the current page to disk. MHTML is the default format that is used to store
the web page on disk. Requires a slot for \l{QWebEngineProfile::}{downloadRequested()}.
- (Added in Qt 5.7)
- \value ViewSource Show the source of the current page in a new tab. Requires implementation of
- \l createWindow() or \l newWindowRequested(). (Added in Qt 5.8)
+ \value [since 5.8] ViewSource Show the source of the current page in a new tab. Requires implementation of
+ \l createWindow() or \l newWindowRequested().
- \value ToggleBold
+ \value [since 5.10] ToggleBold
Toggles boldness for the selection or at the cursor position.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value ToggleItalic
+ Requires \c contenteditable="true".
+ \value [since 5.10] ToggleItalic
Toggles italics for the selection or at the cursor position.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value ToggleUnderline
+ Requires \c contenteditable="true".
+ \value [since 5.10] ToggleUnderline
Toggles underlining of the selection or at the cursor position.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value ToggleStrikethrough
+ Requires \c contenteditable="true".
+ \value [since 5.10] ToggleStrikethrough
Toggles striking through the selection or at the cursor position.
- Requires \c contenteditable="true". (Added in Qt 5.10)
+ Requires \c contenteditable="true".
- \value AlignLeft
+ \value [since 5.10] AlignLeft
Aligns the lines containing the selection or the cursor to the left.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value AlignCenter
+ Requires \c contenteditable="true".
+ \value [since 5.10] AlignCenter
Aligns the lines containing the selection or the cursor at the center.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value AlignRight
+ Requires \c contenteditable="true".
+ \value [since 5.10] AlignRight
Aligns the lines containing the selection or the cursor to the right.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value AlignJustified
+ Requires \c contenteditable="true".
+ \value [since 5.10] AlignJustified
Stretches the lines containing the selection or the cursor so that each
line has equal width.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value Indent
+ Requires \c contenteditable="true".
+ \value [since 5.10] Indent
Indents the lines containing the selection or the cursor.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value Outdent
+ Requires \c contenteditable="true".
+ \value [since 5.10] Outdent
Outdents the lines containing the selection or the cursor.
- Requires \c contenteditable="true". (Added in Qt 5.10)
+ Requires \c contenteditable="true".
- \value InsertOrderedList
+ \value [since 5.10] InsertOrderedList
Inserts an ordered list at the current cursor position, deleting the current selection.
- Requires \c contenteditable="true". (Added in Qt 5.10)
- \value InsertUnorderedList
+ Requires \c contenteditable="true".
+ \value [since 5.10] InsertUnorderedList
Inserts an unordered list at the current cursor position,
deleting the current selection.
- Requires \c contenteditable="true". (Added in Qt 5.10)
+ Requires \c contenteditable="true".
+ \value [since 6.6] ChangeTextDirectionLTR
+ Changes text direction to left-to-right in the focused input element.
+ \value [since 6.6] ChangeTextDirectionRTL
+ Changes text direction to right-to-left in the focused input element.
\omitvalue WebActionCount
*/
@@ -209,8 +210,8 @@
A web browser tab.
\value WebDialog
A window without decoration.
- \value WebBrowserBackgroundTab
- A web browser tab without hiding the current visible WebEngineView. (Added in Qt 5.7)
+ \value [since 5.7] WebBrowserBackgroundTab
+ A web browser tab without hiding the current visible WebEngineView.
*/
/*!
@@ -264,7 +265,7 @@
\value NavigationTypeFormSubmitted The navigation request resulted from a form submission.
\value NavigationTypeBackForward The navigation request resulted from a back or forward action.
\value NavigationTypeReload The navigation request resulted from a reload action.
- \value NavigationTypeRedirect The navigation request resulted from a content or server controlled redirect. This also includes automatic reloads. (Added in Qt 5.14)
+ \value [since 5.14] NavigationTypeRedirect The navigation request resulted from a content or server controlled redirect. This also includes automatic reloads.
\value NavigationTypeOther The navigation request was triggered by other means not covered by the above.
\sa acceptNavigationRequest()
@@ -289,11 +290,18 @@
\value MouseLock
Mouse locking, which locks the mouse pointer to the web view and is typically used in
games.
- \value DesktopVideoCapture
+ \value [since 5.10] DesktopVideoCapture
Video output capture, that is, the capture of the user's display,
- for screen sharing purposes for example. (Added in Qt 5.10)
- \value DesktopAudioVideoCapture
- Both audio and video output capture. (Added in Qt 5.10)
+ for screen sharing purposes for example.
+ \value [since 5.10] DesktopAudioVideoCapture
+ Both audio and video output capture.
+ \value [since 6.8] ClipboardReadWrite
+ Read and write access for the clipboard. If both \l{QWebEngineSettings::JavascriptCanPaste}
+ {JavascriptCanPaste} and \l{QWebEngineSettings::JavascriptCanAccessClipboard}
+ {JavascriptCanAccessClipboard} settings are enabled, this permission will always be granted
+ automatically and no feature requests will be made.
+ \value [since 6.8] LocalFontsAccess
+ Access to the fonts installed on the user's machine. Only available on desktop platforms.
\sa featurePermissionRequested(), featurePermissionRequestCanceled(), setFeaturePermission(), PermissionPolicy
@@ -451,6 +459,9 @@
The action is owned by the QWebEnginePage but you can customize the look by
changing its properties.
+ \l{QWebEnginePage::action(WebAction action)} does not have a default styled icon.
+ Use \l{QWebEngineView::pageAction()} to have an action with a default styled icon.
+
QWebEnginePage also takes care of implementing the action, so that upon
triggering the corresponding action is performed on the page.
@@ -706,6 +717,7 @@
is empty, it is assumed that the content is \c{text/plain,charset=US-ASCII}.
External objects referenced in the content are located relative to \a baseUrl.
+ For external objects with relative URLs to be loaded, \c baseUrl cannot be empty.
The \a data is loaded immediately; external objects are loaded asynchronously.
@@ -812,3 +824,15 @@
\sa url()
*/
+
+/*!
+ \fn void QWebEnginePage::webAuthUxRequested(QWebEngineWebAuthUxRequest *request);
+ \since 6.7
+
+ This signal is emitted when a WebAuth authenticator needs user interaction
+ during the authentication process. These requests are handled by displaying a dialog to the user.
+
+ The \a request contains the information and API required to complete the WebAuth UX request.
+
+ \sa QWebEngineWebAuthUxRequest
+*/
diff --git a/src/core/doc/src/qwebenginesettings_lgpl.qdoc b/src/core/doc/src/qwebenginesettings_lgpl.qdoc
index 5cd1e5419..cd7ff8e8c 100644
--- a/src/core/doc/src/qwebenginesettings_lgpl.qdoc
+++ b/src/core/doc/src/qwebenginesettings_lgpl.qdoc
@@ -15,8 +15,8 @@
\inmodule QtWebEngineCore
QWebEngineSettings allows configuration of browser properties, such as font sizes and
- families, the location of a custom style sheet, and generic attributes, such as JavaScript
- support. Individual attributes are set using the setAttribute() function. The
+ families, and generic attributes, such as JavaScript support.
+ Individual attributes are set using the setAttribute() function. The
\l{QWebEngineSettings::WebAttribute}{WebAttribute} enum further describes each attribute.
Each QWebEnginePage object has its own QWebEngineSettings object, which configures the
@@ -73,7 +73,9 @@
Allows JavaScript programs to read from and write to the clipboard.
Writing to the clipboard is always allowed if it is specifically requested by the user.
See JavascriptCanPaste to also allow pasting the content of the clipboard content from
- JavaScript.
+ JavaScript. Since unrestricted clipboard access is a potential security concern, it is
+ recommended that applications leave this disabled and instead respond to
+ \l{QWebEnginePage::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests.
Disabled by default.
\value LinksIncludedInFocusChain
Includes hyperlinks in the keyboard focus chain. Enabled by default.
@@ -151,8 +153,11 @@
similar to Chrome on desktops. To overwrite the default behavior,
disable this setting. (Added in Qt 5.11)
\value JavascriptCanPaste
- Enables JavaScript \c{execCommand("paste")}. This also requires
- enabling JavascriptCanAccessClipboard.
+ Enables JavaScript \c{execCommand("paste")}. This also requires enabling
+ JavascriptCanAccessClipboard. Since unrestricted clipboard access is a potential
+ security concern, it is recommended that applications leave this disabled
+ and instead respond to \l{QWebEnginePage::ClipboardReadWrite}{ClipboardReadWrite}
+ feature permission requests.
Disabled by default. (Added in Qt 5.11)
\value WebRTCPublicInterfacesOnly
Limits WebRTC to public IP addresses only. When disabled WebRTC may also use
@@ -168,6 +173,13 @@
\value NavigateOnDropEnabled Specifies that navigations can be triggered by dropping URLs on
the view.
Enabled by default. (Added in Qt 6.4)
+ \value ReadingFromCanvasEnabled Specifies that reading from all canvas elements is enabled.
+ This setting will have impact on all HTML5 canvas elements irrespective of origin, and can be disabled
+ to prevent canvas fingerprinting.
+ Enabled by default. (Added in Qt 6.6)
+ \value ForceDarkMode Specifies that all web contents will be rendered using a dark theme.
+ For more information, see \l{https://developer.chrome.com/blog/auto-dark-theme/}{Auto dark theme}.
+ Disabled by default. (Added in Qt 6.7)
*/
/*!
@@ -190,6 +202,24 @@
*/
/*!
+ \enum QWebEngineSettings::ImageAnimationPolicy
+ \since Qt 6.8
+
+ This enum describes how an image animation should be handled when the image frames
+ are rendered for animation.
+
+ \value AllowImageAnimation
+ Allows image animation when the image frames are rendered.
+ \value AnimateImageOnce
+ Animate the image once when the image frames are rendered.
+ \value DisallowImageAnimation
+ Disallows image animation when the image frames are rendered.
+ \omitvalue InheritedImageAnimationPolicy
+
+ \sa imageAnimationPolicy setImageAnimationPolicy resetImageAnimationPolicy
+*/
+
+/*!
\fn void QWebEngineSettings::setFontSize(FontSize type, int size)
Sets the font size for \a type to \a size in pixels.
*/
@@ -277,3 +307,26 @@
Resets the setting of \a attribute to the value specified in the
profile that the page belongs to.
*/
+
+/*!
+ \fn QWebEngineSettings::ImageAnimationPolicy QWebEngineSettings::imageAnimationPolicy() const
+ \since Qt 6.8
+ Returns the currently selected policy for handling image animation when the image frames are rendered.
+ Default is \l{QWebEngineSettings::AllowImageAnimation}.
+ \sa setImageAnimationPolicy resetImageAnimationPolicy
+*/
+
+/*!
+ \fn void QWebEngineSettings::setImageAnimationPolicy(QWebEngineSettings::ImageAnimationPolicy policy)
+ \since Qt 6.8
+ Sets the policy for handling image animation when the image frames are rendered to \a policy.
+ Default is \l{QWebEngineSettings::AllowImageAnimation}.
+ \sa imageAnimationPolicy resetImageAnimationPolicy
+*/
+
+/*!
+ \fn void QWebEngineSettings::resetImageAnimationPolicy()
+ \since Qt 6.7
+ Removes the policy for handling image animation.
+ \sa imageAnimationPolicy setImageAnimationPolicy
+*/
diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp
index 3823268fb..c0fd0d3ee 100644
--- a/src/core/download_manager_delegate_qt.cpp
+++ b/src/core/download_manager_delegate_qt.cpp
@@ -59,10 +59,13 @@ void DownloadManagerDelegateQt::cancelDownload(content::DownloadTargetCallback c
download::DownloadInterruptReason::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED);
}
-void DownloadManagerDelegateQt::cancelDownload(quint32 downloadId)
+bool DownloadManagerDelegateQt::cancelDownload(quint32 downloadId)
{
- if (download::DownloadItem *download = findDownloadById(downloadId))
+ if (download::DownloadItem *download = findDownloadById(downloadId)) {
download->Cancel(/* user_cancel */ true);
+ return true;
+ }
+ return false;
}
void DownloadManagerDelegateQt::pauseDownload(quint32 downloadId)
@@ -102,9 +105,37 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem *
return true;
}
- QString suggestedFilename = toQt(item->GetSuggestedFilename());
+ bool acceptedByDefault = false;
+ QString suggestedFilePath;
+ QString suggestedFilename;
+ bool isSavePageDownload = false;
+ WebContentsAdapterClient *adapterClient = nullptr;
+ if (content::WebContents *webContents = content::DownloadItemUtils::GetWebContents(item)) {
+ WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt *>(webContents->GetDelegate());
+ adapterClient = contentsDelegate->adapterClient();
+ if (SavePageInfo *spi = contentsDelegate->savePageInfo()) {
+ // We end up here when saving non text-based files (MHTML, PDF or images)
+ suggestedFilePath = spi->requestedFilePath;
+ const QFileInfo fileInfo(suggestedFilePath);
+ if (fileInfo.isRelative()) {
+ const QDir downloadDir(m_profileAdapter->downloadPath());
+ suggestedFilePath = downloadDir.absoluteFilePath(suggestedFilePath);
+ }
+ suggestedFilename = fileInfo.fileName();
+
+ if (!suggestedFilePath.isEmpty() && !suggestedFilename.isEmpty())
+ acceptedByDefault = true;
+ isSavePageDownload = true;
+
+ // Clear the delegate's SavePageInfo. It's only valid for the page currently being saved.
+ contentsDelegate->setSavePageInfo(nullptr);
+ }
+ }
+
QString mimeTypeString = toQt(item->GetMimeType());
+ if (suggestedFilename.isEmpty())
+ suggestedFilename = toQt(item->GetSuggestedFilename());
if (suggestedFilename.isEmpty())
suggestedFilename = toQt(net::HttpContentDisposition(item->GetContentDisposition(), net::kCharsetLatin1).filename());
@@ -127,16 +158,12 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem *
QDir defaultDownloadDirectory(m_profileAdapter->downloadPath());
- QString suggestedFilePath = m_profileAdapter->determineDownloadPath(defaultDownloadDirectory.absolutePath(), suggestedFilename, item->GetStartTime().ToTimeT());
+ if (suggestedFilePath.isEmpty())
+ suggestedFilePath = m_profileAdapter->determineDownloadPath(defaultDownloadDirectory.absolutePath(), suggestedFilename, item->GetStartTime().ToTimeT());
item->AddObserver(this);
QList<ProfileAdapterClient*> clients = m_profileAdapter->clients();
if (!clients.isEmpty()) {
- content::WebContents *webContents = content::DownloadItemUtils::GetWebContents(item);
- WebContentsAdapterClient *adapterClient = nullptr;
- if (webContents)
- adapterClient = static_cast<WebContentsDelegateQt *>(webContents->GetDelegate())->adapterClient();
-
Q_ASSERT(m_currentId == item->GetId());
ProfileAdapterClient::DownloadItemInfo info = {
item->GetId(),
@@ -147,10 +174,10 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem *
mimeTypeString,
suggestedFilePath,
ProfileAdapterClient::UnknownSavePageFormat,
- false /* accepted */,
+ acceptedByDefault,
false /* paused */,
false /* done */,
- false /* isSavePageDownload */,
+ isSavePageDownload,
item->GetLastReason(),
adapterClient,
suggestedFilename,
@@ -220,12 +247,18 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content
if (clients.isEmpty())
return;
+ bool acceptedByDefault = false;
+ QString suggestedFilePath;
+ ProfileAdapterClient::SavePageFormat suggestedSaveFormat = ProfileAdapterClient::UnknownSavePageFormat;
WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt *>(
web_contents->GetDelegate());
- const SavePageInfo &spi = contentsDelegate->savePageInfo();
+ if (SavePageInfo *spi = contentsDelegate->savePageInfo()) {
+ suggestedFilePath = spi->requestedFilePath;
+ suggestedSaveFormat = static_cast<ProfileAdapterClient::SavePageFormat>(spi->requestedFormat);
+ // Clear the delegate's SavePageInfo. It's only valid for the page currently being saved.
+ contentsDelegate->setSavePageInfo(nullptr);
+ }
- bool acceptedByDefault = false;
- QString suggestedFilePath = spi.requestedFilePath;
if (suggestedFilePath.isEmpty()) {
suggestedFilePath = QFileInfo(toQt(suggested_path.AsUTF8Unsafe())).completeBaseName()
+ QStringLiteral(".mhtml");
@@ -237,14 +270,9 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content
suggestedFilePath = downloadDir.absoluteFilePath(suggestedFilePath);
}
- ProfileAdapterClient::SavePageFormat suggestedSaveFormat
- = static_cast<ProfileAdapterClient::SavePageFormat>(spi.requestedFormat);
if (suggestedSaveFormat == ProfileAdapterClient::UnknownSavePageFormat)
suggestedSaveFormat = ProfileAdapterClient::MimeHtmlSaveFormat;
- // Clear the delegate's SavePageInfo. It's only valid for the page currently being saved.
- contentsDelegate->setSavePageInfo(SavePageInfo());
-
WebContentsAdapterClient *adapterClient = nullptr;
if (web_contents)
adapterClient = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate())->adapterClient();
@@ -254,7 +282,7 @@ void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_content
++m_currentId,
toQt(web_contents->GetURL()),
download::DownloadItem::IN_PROGRESS,
- 0, /* totalBytes */
+ -1, /* totalBytes */
0, /* receivedBytes */
QStringLiteral("application/x-mimearchive"),
suggestedFilePath,
diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h
index f807301d1..cc6d49764 100644
--- a/src/core/download_manager_delegate_qt.h
+++ b/src/core/download_manager_delegate_qt.h
@@ -46,7 +46,7 @@ public:
bool can_save_as_complete,
content::SavePackagePathPickedCallback callback) override;
- void cancelDownload(quint32 downloadId);
+ bool cancelDownload(quint32 downloadId);
void pauseDownload(quint32 downloadId);
void resumeDownload(quint32 downloadId);
void removeDownload(quint32 downloadId);
diff --git a/src/core/extensions/extension_host_delegate_qt.cpp b/src/core/extensions/extension_host_delegate_qt.cpp
index 6cc268e75..aa408a544 100644
--- a/src/core/extensions/extension_host_delegate_qt.cpp
+++ b/src/core/extensions/extension_host_delegate_qt.cpp
@@ -2,11 +2,21 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "extension_host_delegate_qt.h"
+
+#include "desktop_media_controller.h"
+#include "desktop_media_controller_p.h"
#include "extension_web_contents_observer_qt.h"
#include "media_capture_devices_dispatcher.h"
#include "extension_system_qt.h"
+#include "web_contents_view_qt.h"
+#include "base/functional/callback.h"
+#include "content/browser/web_contents/web_contents_impl.h"
#include "extensions/browser/extension_host.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom-shared.h"
+#include "third_party/blink/public/mojom/mediastream/media_stream.mojom.h"
+
+using namespace QtWebEngineCore;
namespace extensions {
@@ -33,26 +43,47 @@ content::JavaScriptDialogManager *ExtensionHostDelegateQt::GetJavaScriptDialogMa
void ExtensionHostDelegateQt::CreateTab(std::unique_ptr<content::WebContents> web_contents,
const std::string &extension_id,
WindowOpenDisposition disposition,
- const gfx::Rect &initial_rect,
+ const blink::mojom::WindowFeatures &features,
bool user_gesture)
{
Q_UNUSED(web_contents);
Q_UNUSED(extension_id);
Q_UNUSED(disposition);
- Q_UNUSED(initial_rect);
+ Q_UNUSED(features);
Q_UNUSED(user_gesture);
Q_UNREACHABLE();
}
+static void processMediaAccessRequest(content::WebContents *webContents,
+ const content::MediaStreamRequest &request,
+ content::MediaResponseCallback callback,
+ content::DesktopMediaID id)
+{
+ MediaCaptureDevicesDispatcher::GetInstance()->processMediaAccessRequest(
+ webContents, request, std::move(callback), id);
+}
+
void ExtensionHostDelegateQt::ProcessMediaAccessRequest(content::WebContents *web_contents,
const content::MediaStreamRequest &request,
content::MediaResponseCallback callback,
const Extension *extension)
{
Q_UNUSED(extension);
-
- QtWebEngineCore::MediaCaptureDevicesDispatcher::GetInstance()->processMediaAccessRequest(web_contents, request, std::move(callback));
+ base::OnceCallback<void(content::DesktopMediaID)> cb = base::BindOnce(
+ &processMediaAccessRequest, web_contents, std::move(request), std::move(callback));
+
+ // ownership is taken by the request
+ auto *controller = new DesktopMediaController(new DesktopMediaControllerPrivate(std::move(cb)));
+ base::WeakPtr<content::WebContents> webContents = web_contents->GetWeakPtr();
+ QObject::connect(controller, &DesktopMediaController::mediaListsInitialized, [controller, webContents]() {
+ if (webContents) {
+ auto *client = WebContentsViewQt::from(static_cast<content::WebContentsImpl *>(webContents.get())->GetView())->client();
+ client->desktopMediaRequested(controller);
+ } else {
+ controller->deleteLater();
+ }
+ });
}
bool ExtensionHostDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *render_frame_host,
diff --git a/src/core/extensions/extension_host_delegate_qt.h b/src/core/extensions/extension_host_delegate_qt.h
index e5577b3fd..1c2688933 100644
--- a/src/core/extensions/extension_host_delegate_qt.h
+++ b/src/core/extensions/extension_host_delegate_qt.h
@@ -20,7 +20,7 @@ public:
void CreateTab(std::unique_ptr<content::WebContents> web_contents,
const std::string &extension_id,
WindowOpenDisposition disposition,
- const gfx::Rect &initial_rect,
+ const blink::mojom::WindowFeatures &features,
bool user_gesture) override;
void ProcessMediaAccessRequest(content::WebContents *web_contents,
const content::MediaStreamRequest &request,
diff --git a/src/core/extensions/extension_system_qt.cpp b/src/core/extensions/extension_system_qt.cpp
index 0f44b8db3..b9f11646d 100644
--- a/src/core/extensions/extension_system_qt.cpp
+++ b/src/core/extensions/extension_system_qt.cpp
@@ -11,7 +11,7 @@
#include "base/base_paths.h"
#include "base/base_switches.h"
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
@@ -43,11 +43,10 @@
#include "extensions/browser/extension_pref_value_map_factory.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_registry.h"
-#include "extensions/browser/info_map.h"
-#include "extensions/browser/notification_types.h"
#include "extensions/browser/quota_service.h"
#include "extensions/browser/renderer_startup_helper.h"
#include "extensions/browser/service_worker_manager.h"
+#include "extensions/browser/task_queue_util.h"
#include "extensions/browser/user_script_manager.h"
#include "extensions/common/constants.h"
#include "extensions/common/manifest_constants.h"
@@ -69,28 +68,28 @@ namespace extensions {
namespace {
-std::string GenerateId(const base::DictionaryValue *manifest, const base::FilePath &path)
+std::string GenerateId(const base::Value::Dict &manifest, const base::FilePath &path)
{
- std::string raw_key;
+ const std::string *raw_key;
std::string id_input;
- CHECK(manifest->GetString(manifest_keys::kPublicKey, &raw_key));
- CHECK(Extension::ParsePEMKeyBytes(raw_key, &id_input));
+ CHECK(raw_key = manifest.FindString(manifest_keys::kPublicKey));
+ CHECK(Extension::ParsePEMKeyBytes(*raw_key, &id_input));
std::string id = crx_file::id_util::GenerateId(id_input);
return id;
}
// Implementation based on ComponentLoader::ParseManifest.
-std::unique_ptr<base::DictionaryValue> ParseManifest(const std::string &manifest_contents)
+absl::optional<base::Value::Dict> ParseManifest(base::StringPiece manifest_contents)
{
JSONStringValueDeserializer deserializer(manifest_contents);
- std::unique_ptr<base::Value> manifest(deserializer.Deserialize(NULL, NULL));
+ std::unique_ptr<base::Value> manifest = deserializer.Deserialize(nullptr, nullptr);
if (!manifest.get() || !manifest->is_dict()) {
LOG(ERROR) << "Failed to parse extension manifest.";
- return NULL;
+ return absl::nullopt;
}
- // Transfer ownership to the caller.
- return base::DictionaryValue::From(std::move(manifest));
+
+ return std::move(*manifest).TakeDict();
}
} // namespace
@@ -129,38 +128,25 @@ public:
void Shutdown() override {}
};
-void ExtensionSystemQt::LoadExtension(std::string extension_id, std::unique_ptr<base::DictionaryValue> manifest, const base::FilePath &directory)
+void ExtensionSystemQt::LoadExtension(std::string extension_id, const base::Value::Dict &manifest, const base::FilePath &directory)
{
int flags = Extension::REQUIRE_KEY;
std::string error;
+
scoped_refptr<const Extension> extension = Extension::Create(
directory,
mojom::ManifestLocation::kComponent,
- *manifest,
+ manifest,
flags,
&error);
if (!extension.get())
LOG(ERROR) << error;
- content::GetIOThreadTaskRunner({})->PostTask(FROM_HERE,
- base::BindOnce(&InfoMap::AddExtension,
- base::Unretained(info_map()),
- base::RetainedRef(extension),
- base::Time::Now(),
- true,
- false));
extension_registry_->AddEnabled(extension.get());
NotifyExtensionLoaded(extension.get());
}
-void ExtensionSystemQt::OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension)
-{
- extension_registry_->AddReady(extension);
- if (extension_registry_->enabled_extensions().Contains(extension->id()))
- extension_registry_->TriggerOnReady(extension.get());
-}
-
// Implementation based on ExtensionService::NotifyExtensionLoaded.
void ExtensionSystemQt::NotifyExtensionLoaded(const Extension *extension)
{
@@ -170,11 +156,7 @@ void ExtensionSystemQt::NotifyExtensionLoaded(const Extension *extension)
// that the request context doesn't yet know about. The profile is responsible
// for ensuring its URLRequestContexts appropriately discover the loaded
// extension.
- RegisterExtensionWithRequestContexts(
- extension,
- base::BindRepeating(&ExtensionSystemQt::OnExtensionRegisteredWithRequestContexts,
- weak_ptr_factory_.GetWeakPtr(),
- base::WrapRefCounted(extension)));
+ ActivateTaskQueueForExtension(browser_context_, extension);
// Tell renderers about the loaded extension.
renderer_helper_->OnExtensionLoaded(*extension);
@@ -191,8 +173,10 @@ void ExtensionSystemQt::NotifyExtensionLoaded(const Extension *extension)
#if BUILDFLAG(ENABLE_PLUGINS)
// Register plugins included with the extension.
// Implementation based on PluginManager::OnExtensionLoaded.
+ bool plugins_changed = false;
const MimeTypesHandler *handler = MimeTypesHandler::GetHandler(extension);
if (handler && handler->HasPlugin()) {
+ plugins_changed = true;
content::WebPluginInfo info;
info.type = content::WebPluginInfo::PLUGIN_TYPE_BROWSER_PLUGIN;
info.name = base::UTF8ToUTF16(extension->name());
@@ -214,7 +198,13 @@ void ExtensionSystemQt::NotifyExtensionLoaded(const Extension *extension)
plugin_service->RefreshPlugins();
plugin_service->RegisterInternalPlugin(info, true);
}
+ if (plugins_changed)
+ content::PluginService::GetInstance()->PurgePluginListCache(browser_context_, false);
#endif // BUILDFLAG(ENABLE_PLUGINS)
+
+ extension_registry_->AddReady(extension);
+ if (extension_registry_->enabled_extensions().Contains(extension->id()))
+ extension_registry_->TriggerOnReady(extension);
}
bool ExtensionSystemQt::FinishDelayedInstallationIfReady(const std::string &extension_id, bool install_immediately)
@@ -269,13 +259,6 @@ scoped_refptr<value_store::ValueStoreFactory> ExtensionSystemQt::store_factory()
return store_factory_;
}
-InfoMap *ExtensionSystemQt::info_map()
-{
- if (!info_map_.get())
- info_map_ = new InfoMap;
- return info_map_.get();
-}
-
QuotaService *ExtensionSystemQt::quota_service()
{
return quota_service_.get();
@@ -331,24 +314,26 @@ void ExtensionSystemQt::Init(bool extensions_enabled)
std::string pdf_manifest = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(IDR_PDF_MANIFEST);
base::ReplaceFirstSubstringAfterOffset(&pdf_manifest, 0, "<NAME>", "chromium-pdf");
- std::unique_ptr<base::DictionaryValue> pdfManifestDict = ParseManifest(pdf_manifest);
+ auto pdfManifestDict = ParseManifest(pdf_manifest);
+ CHECK(pdfManifestDict);
base::FilePath path;
base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &path);
path = path.Append(base::FilePath(FILE_PATH_LITERAL("pdf")));
- std::string id = GenerateId(pdfManifestDict.get(), path);
- LoadExtension(id, std::move(pdfManifestDict), path);
+ std::string id = GenerateId(pdfManifestDict.value(), path);
+ LoadExtension(id, pdfManifestDict.value(), path);
}
#endif // BUILDFLAG(ENABLE_PDF)
#if BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION)
{
std::string hangout_manifest = ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(IDR_HANGOUT_SERVICES_MANIFEST);
- std::unique_ptr<base::DictionaryValue> hangoutManifestDict = ParseManifest(hangout_manifest);
+ auto hangoutManifestDict = ParseManifest(hangout_manifest);
+ CHECK(hangoutManifestDict);
base::FilePath path;
base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &path);
path = path.Append(base::FilePath(FILE_PATH_LITERAL("hangout_services")));
- std::string id = GenerateId(hangoutManifestDict.get(), path);
- LoadExtension(id, std::move(hangoutManifestDict), path);
+ std::string id = GenerateId(hangoutManifestDict.value(), path);
+ LoadExtension(id, hangoutManifestDict.value(), path);
}
#endif // BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION)
}
@@ -358,8 +343,6 @@ void ExtensionSystemQt::InitForRegularProfile(bool extensions_enabled)
{
if (initialized_)
return; // Already initialized.
- // The InfoMap needs to be created before the ProcessManager.
- info_map();
Init(extensions_enabled);
}
@@ -369,27 +352,6 @@ std::unique_ptr<ExtensionSet> ExtensionSystemQt::GetDependentExtensions(const Ex
return base::WrapUnique(new ExtensionSet());
}
-void ExtensionSystemQt::RegisterExtensionWithRequestContexts(const Extension *extension,
- base::OnceClosure callback)
-{
- base::Time install_time = base::Time::Now();
-
- bool incognito_enabled = false;
- bool notifications_disabled = false;
-
- content::GetIOThreadTaskRunner({})->PostTaskAndReply(FROM_HERE,
- base::BindOnce(&InfoMap::AddExtension, info_map(),
- base::RetainedRef(extension), install_time, incognito_enabled,
- notifications_disabled),
- std::move(callback));
-}
-
-void ExtensionSystemQt::UnregisterExtensionWithRequestContexts(const std::string &extension_id)
-{
- content::GetIOThreadTaskRunner({})->PostTask(FROM_HERE,
- base::BindOnce(&InfoMap::RemoveExtension, info_map(), extension_id));
-}
-
bool ExtensionSystemQt::is_ready() const
{
return ready_.is_signaled();
diff --git a/src/core/extensions/extension_system_qt.h b/src/core/extensions/extension_system_qt.h
index 02fbaee37..c213671a7 100644
--- a/src/core/extensions/extension_system_qt.h
+++ b/src/core/extensions/extension_system_qt.h
@@ -58,15 +58,9 @@ public:
StateStore *rules_store() override;
StateStore *dynamic_user_scripts_store() override;
scoped_refptr<value_store::ValueStoreFactory> store_factory() override;
- InfoMap *info_map() override;
QuotaService *quota_service() override;
AppSorting *app_sorting() override;
- void RegisterExtensionWithRequestContexts(const Extension *extension,
- base::OnceClosure callback) override;
-
- void UnregisterExtensionWithRequestContexts(const std::string &extension_id) override;
-
ContentVerifier *content_verifier() override;
std::unique_ptr<ExtensionSet> GetDependentExtensions(const Extension *extension) override;
@@ -77,23 +71,17 @@ public:
const base::OneShotEvent &ready() const override { return ready_; }
bool is_ready() const override;
- void PerformActionBasedOnOmahaAttributes(const std::string &, const base::Value &) override { /* fixme? */}
+ void PerformActionBasedOnOmahaAttributes(const std::string &, const base::Value::Dict &) override { /* fixme? */}
private:
- void OnExtensionRegisteredWithRequestContexts(scoped_refptr<const extensions::Extension> extension);
-
void NotifyExtensionLoaded(const Extension *extension);
- void LoadExtension(std::string extension_id, std::unique_ptr<base::DictionaryValue> manifest, const base::FilePath &directory);
- // The services that are shared between normal and incognito profiles.
-
- // Data to be accessed on the IO thread. Must outlive process_manager_.
- scoped_refptr<InfoMap> info_map_;
+ void LoadExtension(std::string extension_id, const base::Value::Dict &manifest, const base::FilePath &directory);
+ // The services that are shared between normal and incognito profiles.
std::unique_ptr<ServiceWorkerManager> service_worker_manager_;
std::unique_ptr<QuotaService> quota_service_;
std::unique_ptr<UserScriptManager> user_script_manager_;
-
// For verifying the contents of extensions read from disk.
scoped_refptr<ContentVerifier> content_verifier_;
base::OneShotEvent ready_;
diff --git a/src/core/extensions/extensions_api_client_qt.cpp b/src/core/extensions/extensions_api_client_qt.cpp
index 3d86c65f7..678c252cc 100644
--- a/src/core/extensions/extensions_api_client_qt.cpp
+++ b/src/core/extensions/extensions_api_client_qt.cpp
@@ -7,6 +7,7 @@
// found in the LICENSE file.
#include "extensions_api_client_qt.h"
+#include "file_system_delegate_qt.h"
#include "messaging_delegate_qt.h"
#include <memory>
@@ -18,10 +19,6 @@
#include "pdf/buildflags.h"
#include "printing/buildflags/buildflags.h"
-#if BUILDFLAG(ENABLE_PDF)
-#include "components/pdf/browser/pdf_web_contents_helper.h"
-#endif
-
#if BUILDFLAG(ENABLE_PRINTING) && BUILDFLAG(ENABLE_PRINT_PREVIEW)
#include "printing/print_view_manager_qt.h"
#endif
@@ -39,9 +36,16 @@ AppViewGuestDelegate *ExtensionsAPIClientQt::CreateAppViewGuestDelegate() const
return nullptr;
}
-std::unique_ptr<guest_view::GuestViewManagerDelegate> ExtensionsAPIClientQt::CreateGuestViewManagerDelegate(content::BrowserContext *context) const
+FileSystemDelegate *ExtensionsAPIClientQt::GetFileSystemDelegate()
+{
+ if (!m_fileSystemDelegate)
+ m_fileSystemDelegate = std::make_unique<FileSystemDelegateQt>();
+ return m_fileSystemDelegate.get();
+}
+
+std::unique_ptr<guest_view::GuestViewManagerDelegate> ExtensionsAPIClientQt::CreateGuestViewManagerDelegate() const
{
- return std::make_unique<extensions::ExtensionsGuestViewManagerDelegate>(context);
+ return std::make_unique<extensions::ExtensionsGuestViewManagerDelegate>();
}
std::unique_ptr<MimeHandlerViewGuestDelegate> ExtensionsAPIClientQt::CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest *guest) const
diff --git a/src/core/extensions/extensions_api_client_qt.h b/src/core/extensions/extensions_api_client_qt.h
index 7eb74b96c..e7838138c 100644
--- a/src/core/extensions/extensions_api_client_qt.h
+++ b/src/core/extensions/extensions_api_client_qt.h
@@ -13,6 +13,7 @@
namespace extensions {
+class FileSystemDelegate;
class MessagingDelegate;
class ExtensionsAPIClientQt : public ExtensionsAPIClient
@@ -22,14 +23,16 @@ public:
// ExtensionsAPIClient implementation.
AppViewGuestDelegate *CreateAppViewGuestDelegate() const override;
+ FileSystemDelegate *GetFileSystemDelegate() override;
std::unique_ptr<guest_view::GuestViewManagerDelegate>
- CreateGuestViewManagerDelegate(content::BrowserContext *context) const override;
+ CreateGuestViewManagerDelegate() const override;
std::unique_ptr<MimeHandlerViewGuestDelegate>
CreateMimeHandlerViewGuestDelegate(MimeHandlerViewGuest *guest) const override;
void AttachWebContentsHelpers(content::WebContents *web_contents) const override;
MessagingDelegate *GetMessagingDelegate() override;
private:
+ std::unique_ptr<FileSystemDelegate> m_fileSystemDelegate;
std::unique_ptr<MessagingDelegate> m_messagingDelegate;
};
diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp
index ab44c23eb..19fc6c808 100644
--- a/src/core/extensions/extensions_browser_client_qt.cpp
+++ b/src/core/extensions/extensions_browser_client_qt.cpp
@@ -19,9 +19,9 @@
#include "chrome/browser/profiles/profile.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_frame_host.h"
+#include "extensions/browser/api/core_extensions_browser_api_provider.h"
#include "extensions/browser/api/extensions_api_client.h"
#include "extensions/browser/api/runtime/runtime_api_delegate.h"
-#include "extensions/browser/core_extensions_browser_api_provider.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host_delegate.h"
#include "extensions/browser/extension_protocols.h"
@@ -79,7 +79,7 @@ scoped_refptr<base::RefCountedMemory> GetResource(int resource_id, const std::st
base::StringPiece input(reinterpret_cast<const char *>(bytes->front()), bytes->size());
std::string temp_str = ui::ReplaceTemplateExpressions(input, *replacements);
DCHECK(!temp_str.empty());
- return base::RefCountedString::TakeString(&temp_str);
+ return base::MakeRefCounted<base::RefCountedString>(std::move(temp_str));
}
return bytes;
}
@@ -264,7 +264,7 @@ bool ExtensionsBrowserClientQt::AreExtensionsDisabled(const base::CommandLine &c
return false;
}
-bool ExtensionsBrowserClientQt::IsValidContext(BrowserContext *context)
+bool ExtensionsBrowserClientQt::IsValidContext(void *)
{
return true;
}
@@ -291,24 +291,30 @@ BrowserContext *ExtensionsBrowserClientQt::GetOriginalContext(BrowserContext *co
return context;
}
-BrowserContext *ExtensionsBrowserClientQt::GetRedirectedContextInIncognito(BrowserContext *context, bool, bool)
+content::BrowserContext* ExtensionsBrowserClientQt::GetContextRedirectedToOriginal(content::BrowserContext *context, bool)
{
// like in ShellExtensionsBrowserClient:
return context;
}
-BrowserContext *ExtensionsBrowserClientQt::GetContextForRegularAndIncognito(BrowserContext *context, bool, bool)
+content::BrowserContext* ExtensionsBrowserClientQt::GetContextOwnInstance(content::BrowserContext *context, bool)
{
// like in ShellExtensionsBrowserClient:
return context;
}
-BrowserContext *ExtensionsBrowserClientQt::GetRegularProfile(BrowserContext *context, bool, bool)
+content::BrowserContext* ExtensionsBrowserClientQt::GetContextForOriginalOnly(content::BrowserContext *context, bool)
{
// like in ShellExtensionsBrowserClient:
return context;
}
+bool ExtensionsBrowserClientQt::AreExtensionsDisabledForContext(content::BrowserContext*)
+{
+ // like in ShellExtensionsBrowserClient:
+ return false;
+}
+
bool ExtensionsBrowserClientQt::IsGuestSession(BrowserContext *context) const
{
return context->IsOffTheRecord();
@@ -531,4 +537,10 @@ void ExtensionsBrowserClientQt::SetAPIClientForTest(ExtensionsAPIClient *api_cli
api_client_.reset(api_client);
}
+media_device_salt::MediaDeviceSaltService *ExtensionsBrowserClientQt::GetMediaDeviceSaltService(content::BrowserContext *context)
+{
+ // Not needed for QWE
+ return nullptr;
+}
+
} // namespace extensions
diff --git a/src/core/extensions/extensions_browser_client_qt.h b/src/core/extensions/extensions_browser_client_qt.h
index 78b56d920..bcc8f142b 100644
--- a/src/core/extensions/extensions_browser_client_qt.h
+++ b/src/core/extensions/extensions_browser_client_qt.h
@@ -29,15 +29,15 @@ public:
bool IsShuttingDown() override;
bool AreExtensionsDisabled(const base::CommandLine &command_line,
content::BrowserContext *context) override;
- bool IsValidContext(content::BrowserContext *context) override;
+ bool IsValidContext(void*) override;
bool IsSameContext(content::BrowserContext *first,
content::BrowserContext *second) override;
bool HasOffTheRecordContext(content::BrowserContext *context) override;
content::BrowserContext *GetOffTheRecordContext(content::BrowserContext *context) override;
content::BrowserContext *GetOriginalContext(content::BrowserContext *context) override;
- content::BrowserContext *GetRedirectedContextInIncognito(content::BrowserContext *context, bool, bool) override;
- content::BrowserContext *GetContextForRegularAndIncognito(content::BrowserContext *context, bool, bool) override;
- content::BrowserContext *GetRegularProfile(content::BrowserContext *context, bool, bool) override;
+ content::BrowserContext *GetContextRedirectedToOriginal(content::BrowserContext*, bool) override;
+ content::BrowserContext *GetContextOwnInstance(content::BrowserContext*, bool) override;
+ content::BrowserContext *GetContextForOriginalOnly(content::BrowserContext*, bool) override;
bool IsGuestSession(content::BrowserContext *context) const override;
bool IsExtensionIncognitoEnabled(const std::string &extension_id, content::BrowserContext *context) const override;
bool CanExtensionCrossIncognito(const Extension *extension, content::BrowserContext *context) const override;
@@ -104,6 +104,10 @@ public:
// Sets the API client.
void SetAPIClientForTest(ExtensionsAPIClient *api_client);
+ bool AreExtensionsDisabledForContext(content::BrowserContext*) override;
+
+ media_device_salt::MediaDeviceSaltService *GetMediaDeviceSaltService(content::BrowserContext *context) override;
+
private:
// Support for extension APIs.
std::unique_ptr<ExtensionsAPIClient> api_client_;
diff --git a/src/core/extensions/file_system_delegate_qt.cpp b/src/core/extensions/file_system_delegate_qt.cpp
new file mode 100644
index 000000000..7c1c5bbd8
--- /dev/null
+++ b/src/core/extensions/file_system_delegate_qt.cpp
@@ -0,0 +1,146 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "file_system_delegate_qt.h"
+
+#include "select_file_dialog_factory_qt.h"
+#include "type_conversion.h"
+
+#include "base/files/file_path.h"
+#include "base/files/file_path.h"
+#include "base/functional/callback.h"
+#include "base/functional/callback.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/browser/api/file_system/file_system_delegate.h"
+#include "extensions/browser/extension_function.h"
+#include "ui/shell_dialogs/selected_file_info.h"
+
+#include <QStandardPaths>
+
+namespace extensions {
+
+FileEntryPickerQt::FileEntryPickerQt(
+ content::WebContents *web_contents,
+ const base::FilePath &suggested_name,
+ const ui::SelectFileDialog::FileTypeInfo *file_type_info,
+ ui::SelectFileDialog::Type picker_type,
+ FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+ base::OnceClosure file_selection_canceled_callback)
+ : m_filesSelectedCallback(std::move(files_selected_callback))
+ , m_fileSelectionCanceledCallback(std::move(file_selection_canceled_callback))
+{
+ const GURL caller = web_contents->GetPrimaryMainFrame()->GetLastCommittedURL();
+ m_selectFileDialog = ui::SelectFileDialog::Create(
+ this, std::make_unique<QtWebEngineCore::SelectFilePolicyQt>(web_contents));
+ m_selectFileDialog->SelectFile(
+ picker_type, std::u16string(), suggested_name, file_type_info, 0,
+ base::FilePath::StringType(), nullptr, nullptr, &caller);
+}
+
+FileEntryPickerQt::~FileEntryPickerQt() = default;
+
+void FileEntryPickerQt::FileSelected(const base::FilePath &path,
+ int index,
+ void *params)
+{
+ MultiFilesSelected({path}, params);
+}
+
+void FileEntryPickerQt::FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file,
+ int index,
+ void *params)
+{
+ FileSelected(file.file_path, index, params);
+}
+
+void FileEntryPickerQt::MultiFilesSelected(const std::vector<base::FilePath>& files,
+ void* params)
+{
+ Q_UNUSED(params);
+ std::move(m_filesSelectedCallback).Run(files);
+ delete this;
+}
+
+void FileEntryPickerQt::MultiFilesSelectedWithExtraInfo(
+ const std::vector<ui::SelectedFileInfo> &files,
+ void *params)
+{
+ std::vector<base::FilePath> paths;
+ for (const auto& file : files)
+ paths.push_back(file.file_path);
+ MultiFilesSelected(paths, params);
+}
+
+void FileEntryPickerQt::FileSelectionCanceled(void *params)
+{
+ std::move(m_fileSelectionCanceledCallback).Run();
+ delete this;
+}
+
+FileSystemDelegateQt::FileSystemDelegateQt()
+{
+}
+
+base::FilePath FileSystemDelegateQt::GetDefaultDirectory()
+{
+ return QtWebEngineCore::toFilePath(
+ QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation));
+}
+
+base::FilePath FileSystemDelegateQt::GetManagedSaveAsDirectory(
+ content::BrowserContext *browser_context,
+ const Extension &extension)
+{
+ Q_UNUSED(browser_context);
+ Q_UNUSED(extension);
+ return base::FilePath();
+}
+
+bool FileSystemDelegateQt::ShowSelectFileDialog(
+ scoped_refptr<ExtensionFunction> extension_function,
+ ui::SelectFileDialog::Type type,
+ const base::FilePath &default_path,
+ const ui::SelectFileDialog::FileTypeInfo *file_type_info,
+ FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+ base::OnceClosure file_selection_canceled_callback)
+{
+ content::WebContents *web_contents = extension_function->GetSenderWebContents();
+ if (!web_contents)
+ return false;
+
+ new FileEntryPickerQt(web_contents, default_path, file_type_info, type,
+ std::move(files_selected_callback),
+ std::move(file_selection_canceled_callback));
+ return true;
+}
+
+void FileSystemDelegateQt::ConfirmSensitiveDirectoryAccess(
+ bool has_write_permission,
+ const std::u16string &app_name,
+ content::WebContents *web_contents,
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel)
+{
+ Q_UNUSED(has_write_permission);
+ Q_UNUSED(app_name);
+ Q_UNUSED(web_contents);
+ Q_UNUSED(on_accept);
+ std::move(on_cancel).Run();
+}
+
+int FileSystemDelegateQt::GetDescriptionIdForAcceptType(const std::string &accept_type)
+{
+ Q_UNUSED(accept_type);
+ return 0;
+}
+
+SavedFilesServiceInterface *FileSystemDelegateQt::GetSavedFilesService(
+ content::BrowserContext *browser_context)
+{
+ Q_UNUSED(browser_context);
+ return nullptr;
+}
+
+} // namespace extensions
diff --git a/src/core/extensions/file_system_delegate_qt.h b/src/core/extensions/file_system_delegate_qt.h
new file mode 100644
index 000000000..1e9d87c38
--- /dev/null
+++ b/src/core/extensions/file_system_delegate_qt.h
@@ -0,0 +1,89 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef FILE_SYSTEM_DELEGATE_QT_H
+#define FILE_SYSTEM_DELEGATE_QT_H
+
+#include "extensions/browser/api/file_system/file_system_delegate.h"
+
+#include "base/files/file_path.h"
+#include "base/functional/callback.h"
+#include "base/memory/ref_counted.h"
+#include "extensions/browser/extension_function.h"
+#include "ui/shell_dialogs/select_file_dialog.h"
+
+#include <memory>
+#include <vector>
+
+namespace content {
+class BrowserContext;
+} // namespace content
+
+namespace extensions {
+
+class FileEntryPickerQt : public ui::SelectFileDialog::Listener {
+public:
+ FileEntryPickerQt(
+ content::WebContents *web_contents,
+ const base::FilePath &suggested_name,
+ const ui::SelectFileDialog::FileTypeInfo *file_type_info,
+ ui::SelectFileDialog::Type picker_type,
+ FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+ base::OnceClosure file_selection_canceled_callback);
+
+ FileEntryPickerQt(const FileEntryPickerQt &) = delete;
+ FileEntryPickerQt &operator=(const FileEntryPickerQt &) = delete;
+
+private:
+ ~FileEntryPickerQt() override;
+
+ // ui::SelectFileDialog::Listener implementation.
+ void FileSelected(const base::FilePath &path,
+ int index,
+ void *params) override;
+ void FileSelectedWithExtraInfo(const ui::SelectedFileInfo &file,
+ int index,
+ void *params) override;
+ void MultiFilesSelected(const std::vector<base::FilePath> &files,
+ void *params) override;
+ void MultiFilesSelectedWithExtraInfo(
+ const std::vector<ui::SelectedFileInfo> &files,
+ void *params) override;
+ void FileSelectionCanceled(void *params) override;
+
+ FileSystemDelegate::FilesSelectedCallback m_filesSelectedCallback;
+ base::OnceClosure m_fileSelectionCanceledCallback;
+ scoped_refptr<ui::SelectFileDialog> m_selectFileDialog;
+};
+
+class FileSystemDelegateQt : public FileSystemDelegate
+{
+public:
+ FileSystemDelegateQt();
+
+ // FileSystemDelegate implementation
+ virtual base::FilePath GetDefaultDirectory() override;
+ virtual base::FilePath GetManagedSaveAsDirectory(
+ content::BrowserContext *browser_context,
+ const Extension &extension) override;
+ virtual bool ShowSelectFileDialog(
+ scoped_refptr<ExtensionFunction> extension_function,
+ ui::SelectFileDialog::Type type,
+ const base::FilePath &default_path,
+ const ui::SelectFileDialog::FileTypeInfo *file_types,
+ FileSystemDelegate::FilesSelectedCallback files_selected_callback,
+ base::OnceClosure file_selection_canceled_callback) override;
+ virtual void ConfirmSensitiveDirectoryAccess(
+ bool has_write_permission,
+ const std::u16string &app_name,
+ content::WebContents *web_contents,
+ base::OnceClosure on_accept,
+ base::OnceClosure on_cancel) override;
+ virtual int GetDescriptionIdForAcceptType(const std::string &accept_type) override;
+ virtual SavedFilesServiceInterface *GetSavedFilesService(
+ content::BrowserContext *browser_context) override;
+};
+
+} // namespace extensions
+
+#endif // FILE_SYSTEM_DELEGATE_QT_H
diff --git a/src/core/extensions/pdf_iframe_navigation_throttle_qt.cpp b/src/core/extensions/pdf_iframe_navigation_throttle_qt.cpp
index 5a93b4b84..a494e2f49 100644
--- a/src/core/extensions/pdf_iframe_navigation_throttle_qt.cpp
+++ b/src/core/extensions/pdf_iframe_navigation_throttle_qt.cpp
@@ -9,6 +9,7 @@
#include "extensions/pdf_iframe_navigation_throttle_qt.h"
+#include "base/task/sequenced_task_runner.h"
#include "chrome/grit/renderer_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/download_utils.h"
@@ -25,19 +26,18 @@
#include "ui/base/webui/jstemplate_builder.h"
#include "ui/base/webui/web_ui_util.h"
+#include "pdf_util_qt.h"
+
#include <QtGlobal>
namespace extensions {
-constexpr char kPDFMimeType[] = "application/pdf";
-
// Used to scope the posted navigation task to the lifetime of |web_contents|.
class PdfWebContentsLifetimeHelper : public content::WebContentsUserData<PdfWebContentsLifetimeHelper>
{
public:
explicit PdfWebContentsLifetimeHelper(content::WebContents *web_contents)
: content::WebContentsUserData<PdfWebContentsLifetimeHelper>(*web_contents)
- , web_contents_(web_contents)
{}
base::WeakPtr<PdfWebContentsLifetimeHelper> GetWeakPtr()
@@ -47,13 +47,12 @@ public:
void NavigateIFrameToPlaceholder(const content::OpenURLParams &url_params)
{
- web_contents_->OpenURL(url_params);
+ GetWebContents().OpenURL(url_params);
}
private:
friend class content::WebContentsUserData<PdfWebContentsLifetimeHelper>;
- content::WebContents *const web_contents_;
base::WeakPtrFactory<PdfWebContentsLifetimeHelper> weak_factory_{this};
WEB_CONTENTS_USER_DATA_KEY_DECL();
@@ -74,10 +73,11 @@ bool IsPDFPluginEnabled(content::NavigationHandle *navigation_handle, bool *is_s
content::WebPluginInfo plugin_info;
// Will check WebEngineSettings by PluginServiceFilterQt
return content::PluginService::GetInstance()->GetPluginInfo(
- process_id, routing_id, nullptr, navigation_handle->GetURL(),
- kPDFMimeType,
- false /* allow_wildcard */, is_stale, &plugin_info,
- nullptr /* actual_mime_type */);
+ process_id, routing_id,
+ navigation_handle->GetWebContents()->GetBrowserContext(),
+ navigation_handle->GetURL(),
+ QtWebEngineCore::kPDFMimeType, false /* allow_wildcard */,
+ is_stale, &plugin_info, nullptr /* actual_mime_type */);
}
std::string GetPDFPlaceholderHTML(const GURL &pdf_url)
@@ -119,12 +119,15 @@ content::NavigationThrottle::ThrottleCheckResult PDFIFrameNavigationThrottleQt::
std::string mime_type;
response_headers->GetMimeType(&mime_type);
- if (mime_type != kPDFMimeType)
+ if (mime_type != QtWebEngineCore::kPDFMimeType)
return content::NavigationThrottle::PROCEED;
// We MUST download responses marked as attachments rather than showing
// a placeholder.
- if (content::download_utils::MustDownload(navigation_handle()->GetURL(), response_headers, mime_type))
+ if (content::download_utils::MustDownload(navigation_handle()->GetWebContents()
+ ? navigation_handle()->GetWebContents()->GetBrowserContext()
+ : nullptr,
+ navigation_handle()->GetURL(), response_headers, mime_type))
return content::NavigationThrottle::PROCEED;
bool is_stale = false;
@@ -182,7 +185,7 @@ void PDFIFrameNavigationThrottleQt::LoadPlaceholderHTML()
PdfWebContentsLifetimeHelper::CreateForWebContents(web_contents);
PdfWebContentsLifetimeHelper *helper = PdfWebContentsLifetimeHelper::FromWebContents(web_contents);
- base::SequencedTaskRunnerHandle::Get()->PostTask(
+ base::SequencedTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&PdfWebContentsLifetimeHelper::NavigateIFrameToPlaceholder,
helper->GetWeakPtr(), std::move(params)));
diff --git a/src/core/favicon_service_factory_qt.cpp b/src/core/favicon_service_factory_qt.cpp
index d76bfab11..dd2a1979a 100644
--- a/src/core/favicon_service_factory_qt.cpp
+++ b/src/core/favicon_service_factory_qt.cpp
@@ -23,12 +23,17 @@ void HistoryClientQt::OnHistoryServiceCreated(history::HistoryService *history_s
void HistoryClientQt::Shutdown() { }
-bool HistoryClientQt::CanAddURL(const GURL &url)
+static bool CanAddURL(const GURL &url)
{
Q_UNUSED(url);
return true;
}
+history::CanAddURLCallback HistoryClientQt::GetThreadSafeCanAddURLCallback() const
+{
+ return base::BindRepeating(&CanAddURL);
+}
+
void HistoryClientQt::NotifyProfileError(sql::InitStatus init_status,
const std::string &diagnostics)
{
@@ -41,7 +46,7 @@ std::unique_ptr<history::HistoryBackendClient> HistoryClientQt::CreateBackendCli
return nullptr;
}
-void HistoryClientQt::UpdateBookmarkLastUsedTime(int64_t /*bookmark_node_id*/, base::Time /*time*/)
+void HistoryClientQt::UpdateBookmarkLastUsedTime(const base::Uuid &, base::Time /*time*/)
{
}
@@ -84,7 +89,7 @@ HistoryServiceFactoryQt::BuildServiceInstanceFor(content::BrowserContext *contex
std::unique_ptr<history::HistoryService> historyService(
new history::HistoryService(std::make_unique<HistoryClientQt>(), nullptr));
- if (!historyService->Init(history::HistoryDatabaseParamsForPath(context->GetPath()))) {
+ if (!historyService->Init(history::HistoryDatabaseParamsForPath(context->GetPath(), version_info::Channel::DEFAULT))) {
return nullptr;
}
return historyService.release();
diff --git a/src/core/favicon_service_factory_qt.h b/src/core/favicon_service_factory_qt.h
index 44a43211e..55d5f3b33 100644
--- a/src/core/favicon_service_factory_qt.h
+++ b/src/core/favicon_service_factory_qt.h
@@ -48,10 +48,10 @@ public:
void OnHistoryServiceCreated(history::HistoryService *history_service) override;
void Shutdown() override;
- bool CanAddURL(const GURL &url) override;
+ history::CanAddURLCallback GetThreadSafeCanAddURLCallback() const override;
void NotifyProfileError(sql::InitStatus init_status, const std::string &diagnostics) override;
std::unique_ptr<history::HistoryBackendClient> CreateBackendClient() override;
- void UpdateBookmarkLastUsedTime(int64_t bookmark_node_id, base::Time time) override;
+ void UpdateBookmarkLastUsedTime(const base::Uuid &, base::Time) override;
};
class HistoryServiceFactoryQt : public BrowserContextKeyedServiceFactory
diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp
index 6ec7258b9..9b4521358 100644
--- a/src/core/file_picker_controller.cpp
+++ b/src/core/file_picker_controller.cpp
@@ -136,7 +136,7 @@ void FilePickerController::accepted(const QVariant &files)
{
QStringList stringList;
- if (files.canConvert(QMetaType::QStringList)) {
+ if (files.canConvert(QMetaType{QMetaType::QStringList})) {
stringList = files.toStringList();
} else if (files.canConvert<QList<QUrl> >()) {
const QList<QUrl> urls = files.value<QList<QUrl>>();
diff --git a/src/core/file_picker_controller.h b/src/core/file_picker_controller.h
index 82c72a9e6..42ffd6a2d 100644
--- a/src/core/file_picker_controller.h
+++ b/src/core/file_picker_controller.h
@@ -22,7 +22,7 @@
namespace QtWebEngineCore {
class FilePickerControllerPrivate;
-class Q_WEBENGINECORE_PRIVATE_EXPORT FilePickerController : public QObject {
+class Q_WEBENGINECORE_EXPORT FilePickerController : public QObject {
Q_OBJECT
public:
enum FileChooserMode {
diff --git a/src/core/file_system_access/file_system_access_permission_context_qt.cpp b/src/core/file_system_access/file_system_access_permission_context_qt.cpp
index bc88f7898..c290aab82 100644
--- a/src/core/file_system_access/file_system_access_permission_context_qt.cpp
+++ b/src/core/file_system_access/file_system_access_permission_context_qt.cpp
@@ -241,6 +241,8 @@ FileSystemAccessPermissionContextQt::GetReadPermissionGrant(const url::Origin &o
break;
case UserAction::kLoadFromStorage:
break;
+ case UserAction::kNone:
+ Q_UNREACHABLE();
}
return existing_grant;
@@ -285,6 +287,8 @@ FileSystemAccessPermissionContextQt::GetWritePermissionGrant(const url::Origin &
case UserAction::kDragAndDrop:
case UserAction::kLoadFromStorage:
break;
+ case UserAction::kNone:
+ Q_UNREACHABLE();
}
return existing_grant;
@@ -360,9 +364,6 @@ base::FilePath FileSystemAccessPermissionContextQt::GetWellKnownDirectoryPath(
{
QStandardPaths::StandardLocation location = QStandardPaths::DocumentsLocation;
switch (directory) {
- case blink::mojom::WellKnownDirectory::kDefault:
- location = QStandardPaths::DocumentsLocation;
- break;
case blink::mojom::WellKnownDirectory::kDirDesktop:
location = QStandardPaths::DesktopLocation;
break;
@@ -453,4 +454,26 @@ std::u16string FileSystemAccessPermissionContextQt::GetPickerTitle(const blink::
return {};
}
+void FileSystemAccessPermissionContextQt::PermissionGrantDestroyed(
+ FileSystemAccessPermissionGrantQt *grant)
+{
+ auto it = m_origins.find(grant->origin());
+ if (it == m_origins.end())
+ return;
+
+ auto &grants =
+ grant->type() == GrantType::kRead ? it->second.read_grants : it->second.write_grants;
+ auto grant_it = grants.find(grant->path());
+
+ if (grant_it == grants.end()) {
+ return;
+ }
+ if (grant_it->second == grant)
+ grants.erase(grant_it);
+}
+
+void FileSystemAccessPermissionContextQt::NotifyEntryMoved(const url::Origin &, const base::FilePath &, const base::FilePath &)
+{
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/file_system_access/file_system_access_permission_context_qt.h b/src/core/file_system_access/file_system_access_permission_context_qt.h
index 29fefee24..06fbfae3f 100644
--- a/src/core/file_system_access/file_system_access_permission_context_qt.h
+++ b/src/core/file_system_access/file_system_access_permission_context_qt.h
@@ -19,7 +19,7 @@ class BrowserContext;
}
namespace QtWebEngineCore {
-
+class FileSystemAccessPermissionGrantQt;
class FileSystemAccessPermissionContextQt : public content::FileSystemAccessPermissionContext,
public KeyedService
{
@@ -52,10 +52,13 @@ public:
GetLastPickedDirectory(const url::Origin &origin, const std::string &id) override;
base::FilePath GetWellKnownDirectoryPath(blink::mojom::WellKnownDirectory directory, const url::Origin &origin) override;
std::u16string GetPickerTitle(const blink::mojom::FilePickerOptionsPtr &) override;
+ void NotifyEntryMoved(const url::Origin &, const base::FilePath &, const base::FilePath &) override;
void NavigatedAwayFromOrigin(const url::Origin &origin);
content::BrowserContext *profile() const { return m_profile; }
+ void PermissionGrantDestroyed(FileSystemAccessPermissionGrantQt *);
+
private:
class PermissionGrantImpl;
diff --git a/src/core/file_system_access/file_system_access_permission_grant_qt.cpp b/src/core/file_system_access/file_system_access_permission_grant_qt.cpp
index 8999bf850..67fa1c8cf 100644
--- a/src/core/file_system_access/file_system_access_permission_grant_qt.cpp
+++ b/src/core/file_system_access/file_system_access_permission_grant_qt.cpp
@@ -22,7 +22,11 @@ FileSystemAccessPermissionGrantQt::FileSystemAccessPermissionGrantQt(
: m_context(context), m_origin(origin), m_path(path), m_handleType(handle_type), m_type(type)
{
}
-
+FileSystemAccessPermissionGrantQt::~FileSystemAccessPermissionGrantQt()
+{
+ if (m_context)
+ m_context->PermissionGrantDestroyed(this);
+}
void FileSystemAccessPermissionGrantQt::RequestPermission(
content::GlobalRenderFrameHostId frame_id, UserActivationState user_activation_state,
base::OnceCallback<void(PermissionRequestOutcome)> callback)
diff --git a/src/core/file_system_access/file_system_access_permission_grant_qt.h b/src/core/file_system_access/file_system_access_permission_grant_qt.h
index 1984b8f2c..829d2b889 100644
--- a/src/core/file_system_access/file_system_access_permission_grant_qt.h
+++ b/src/core/file_system_access/file_system_access_permission_grant_qt.h
@@ -36,6 +36,9 @@ public:
void SetStatus(blink::mojom::PermissionStatus status);
+protected:
+ ~FileSystemAccessPermissionGrantQt() override;
+
private:
void OnPermissionRequestResult(base::OnceCallback<void(PermissionRequestOutcome)> callback,
permissions::PermissionAction result);
diff --git a/src/core/file_system_access/file_system_access_permission_request_controller.h b/src/core/file_system_access/file_system_access_permission_request_controller.h
index f1b446de6..e659f81a7 100644
--- a/src/core/file_system_access/file_system_access_permission_request_controller.h
+++ b/src/core/file_system_access/file_system_access_permission_request_controller.h
@@ -17,7 +17,7 @@ class FileSystemAccessPermissionRequestController : public RequestController
public:
FileSystemAccessPermissionRequestController(const QUrl &origin, const QUrl &filePath,
HandleType handleType, AccessFlags accessType)
- : RequestController(std::move(origin))
+ : RequestController(origin)
, m_filePath(filePath)
, m_handleType(handleType)
, m_accessType(accessType)
diff --git a/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp b/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp
index 7dc5f5211..f77c974d0 100644
--- a/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp
+++ b/src/core/file_system_access/file_system_access_permission_request_controller_impl.cpp
@@ -23,7 +23,7 @@ FileSystemAccessPermissionRequestControllerImpl::FileSystemAccessPermissionReque
const FileSystemAccessPermissionRequestManagerQt::RequestData &request,
base::OnceCallback<void(permissions::PermissionAction result)> callback)
: FileSystemAccessPermissionRequestController(
- toQt(request.origin.GetURL()), toQt(request.path.value()),
+ toQt(request.origin.GetURL()), QUrl::fromLocalFile(toQt(request.path.value())),
(HandleType)request.handle_type, AccessFlags((int)request.access))
, m_callback(std::move(callback))
{
diff --git a/src/core/file_system_access/file_system_access_permission_request_manager_qt.h b/src/core/file_system_access/file_system_access_permission_request_manager_qt.h
index f8746eabf..840854911 100644
--- a/src/core/file_system_access/file_system_access_permission_request_manager_qt.h
+++ b/src/core/file_system_access/file_system_access_permission_request_manager_qt.h
@@ -4,9 +4,9 @@
#ifndef FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_MANAGER_QT_H
#define FILE_SYSTEM_ACCESS_PERMISSION_REQUEST_MANAGER_QT_H
-#include "base/callback_helpers.h"
#include "base/containers/circular_deque.h"
#include "base/files/file_path.h"
+#include "base/functional/callback_helpers.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/file_system_access_permission_context.h"
#include "content/public/browser/web_contents_observer.h"
diff --git a/src/core/find_text_helper.h b/src/core/find_text_helper.h
index 38a0b9d13..6d2e48b63 100644
--- a/src/core/find_text_helper.h
+++ b/src/core/find_text_helper.h
@@ -37,7 +37,7 @@ namespace QtWebEngineCore {
class WebContentsAdapterClient;
-class Q_WEBENGINECORE_PRIVATE_EXPORT FindTextHelper {
+class Q_WEBENGINECORE_EXPORT FindTextHelper {
public:
FindTextHelper(content::WebContents *webContents, WebContentsAdapterClient *viewClient);
~FindTextHelper();
diff --git a/src/core/javascript_dialog_controller.h b/src/core/javascript_dialog_controller.h
index 5845c156c..6c1ee269f 100644
--- a/src/core/javascript_dialog_controller.h
+++ b/src/core/javascript_dialog_controller.h
@@ -23,7 +23,7 @@ namespace QtWebEngineCore {
class JavaScriptDialogControllerPrivate;
-class Q_WEBENGINECORE_PRIVATE_EXPORT JavaScriptDialogController : public QObject {
+class Q_WEBENGINECORE_EXPORT JavaScriptDialogController : public QObject {
Q_OBJECT
public:
~JavaScriptDialogController();
diff --git a/src/core/javascript_dialog_controller_p.h b/src/core/javascript_dialog_controller_p.h
index 8345cd50b..af064250b 100644
--- a/src/core/javascript_dialog_controller_p.h
+++ b/src/core/javascript_dialog_controller_p.h
@@ -15,7 +15,7 @@
// We mean it.
//
-#include "base/callback.h"
+#include "base/functional/callback.h"
#include "content/public/browser/javascript_dialog_manager.h"
#include "web_contents_adapter_client.h"
diff --git a/src/core/location_provider_qt.cpp b/src/core/location_provider_qt.cpp
index c7273eaea..dc0d80aa7 100644
--- a/src/core/location_provider_qt.cpp
+++ b/src/core/location_provider_qt.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "location_provider_qt.h"
@@ -12,12 +12,18 @@
#include <QtCore/QThread>
#include <QtPositioning/QGeoPositionInfoSource>
-#include "base/bind.h"
+#if QT_CONFIG(permissions)
+#include <QtCore/qpermissions.h>
+#endif
+
+#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "content/public/browser/browser_thread.h"
#include "services/device/geolocation/geolocation_provider.h"
#include "services/device/geolocation/geolocation_provider_impl.h"
+#include "services/device/public/mojom/geoposition.mojom.h"
+
namespace QtWebEngineCore {
using content::BrowserThread;
@@ -37,6 +43,7 @@ private Q_SLOTS:
void error(QGeoPositionInfoSource::Error positioningError);
private:
+ void startImpl(bool highAccuracy);
LocationProviderQt *m_locationProvider;
QGeoPositionInfoSource *m_positionInfoSource;
base::WeakPtrFactory<LocationProviderQt> m_locationProviderFactory;
@@ -66,6 +73,38 @@ static bool isHighAccuracySource(const QGeoPositionInfoSource *source)
void QtPositioningHelper::start(bool highAccuracy)
{
DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+ // New Qt permissions API from 6.5.0
+#if QT_CONFIG(permissions)
+ QLocationPermission locationPermission;
+ locationPermission.setAvailability(QLocationPermission::WhenInUse);
+
+ QLocationPermission::Accuracy accuracy = highAccuracy ? QLocationPermission::Precise
+ : QLocationPermission::Approximate;
+ locationPermission.setAccuracy(accuracy);
+
+ switch (qApp->checkPermission(locationPermission)) {
+ case Qt::PermissionStatus::Undetermined:
+ qApp->requestPermission(locationPermission, this,
+ [this, &highAccuracy](const QPermission &permission) {
+ if (permission.status() == Qt::PermissionStatus::Granted)
+ this->startImpl(highAccuracy);
+ });
+
+ return;
+ case Qt::PermissionStatus::Denied:
+ qWarning("Failed to initialize location provider: The user does not have the right "
+ "permissions or has denied the permission request.");
+ return;
+ case Qt::PermissionStatus::Granted:
+ break; // Proceed
+ }
+#endif
+ startImpl(highAccuracy);
+}
+
+void QtPositioningHelper::startImpl(bool highAccuracy){
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (!m_positionInfoSource)
m_positionInfoSource = QGeoPositionInfoSource::createDefaultSource(this);
if (!m_positionInfoSource) {
@@ -124,59 +163,59 @@ void QtPositioningHelper::updatePosition(const QGeoPositionInfo &pos)
if (!pos.isValid())
return;
Q_ASSERT(m_positionInfoSource->error() == QGeoPositionInfoSource::NoError);
- device::mojom::Geoposition newPos;
- newPos.error_code = device::mojom::Geoposition::ErrorCode::NONE;
- newPos.error_message.clear();
+ auto newPos = device::mojom::Geoposition::New();
- newPos.timestamp = toTime(pos.timestamp());
- newPos.latitude = pos.coordinate().latitude();
- newPos.longitude = pos.coordinate().longitude();
+ newPos->timestamp = toTime(pos.timestamp());
+ newPos->latitude = pos.coordinate().latitude();
+ newPos->longitude = pos.coordinate().longitude();
const double altitude = pos.coordinate().altitude();
if (!qIsNaN(altitude))
- newPos.altitude = altitude;
+ newPos->altitude = altitude;
// Chromium's geoposition needs a valid (as in >=0.) accuracy field.
// try and get an accuracy estimate from QGeoPositionInfo.
// If we don't have any accuracy info, 100m seems a pesimistic enough default.
if (!pos.hasAttribute(QGeoPositionInfo::VerticalAccuracy) && !pos.hasAttribute(QGeoPositionInfo::HorizontalAccuracy))
- newPos.accuracy = 100;
+ newPos->accuracy = 100;
else {
const double vAccuracy = pos.hasAttribute(QGeoPositionInfo::VerticalAccuracy) ? pos.attribute(QGeoPositionInfo::VerticalAccuracy) : 0;
const double hAccuracy = pos.hasAttribute(QGeoPositionInfo::HorizontalAccuracy) ? pos.attribute(QGeoPositionInfo::HorizontalAccuracy) : 0;
- newPos.accuracy = sqrt(vAccuracy * vAccuracy + hAccuracy * hAccuracy);
+ newPos->accuracy = sqrt(vAccuracy * vAccuracy + hAccuracy * hAccuracy);
}
// And now the "nice to have" fields (-1 means invalid).
- newPos.speed = pos.hasAttribute(QGeoPositionInfo::GroundSpeed) ? pos.attribute(QGeoPositionInfo::GroundSpeed) : -1;
- newPos.heading = pos.hasAttribute(QGeoPositionInfo::Direction) ? pos.attribute(QGeoPositionInfo::Direction) : -1;
+ newPos->speed = pos.hasAttribute(QGeoPositionInfo::GroundSpeed) ? pos.attribute(QGeoPositionInfo::GroundSpeed) : -1;
+ newPos->heading = pos.hasAttribute(QGeoPositionInfo::Direction) ? pos.attribute(QGeoPositionInfo::Direction) : -1;
+ auto newResult = device::mojom::GeopositionResult::NewPosition(std::move(newPos));
if (m_locationProvider)
- postToLocationProvider(base::BindOnce(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), newPos));
+ postToLocationProvider(base::BindOnce(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), std::move(newResult)));
}
void QtPositioningHelper::error(QGeoPositionInfoSource::Error positioningError)
{
Q_ASSERT(positioningError != QGeoPositionInfoSource::NoError);
- device::mojom::Geoposition newPos;
+ auto newError = device::mojom::GeopositionError::New();
switch (positioningError) {
case QGeoPositionInfoSource::AccessError:
- newPos.error_code = device::mojom::Geoposition::ErrorCode::PERMISSION_DENIED;
+ newError->error_code = device::mojom::GeopositionErrorCode::kPermissionDenied;
break;
case QGeoPositionInfoSource::UpdateTimeoutError:
// content::Geoposition::ERROR_CODE_TIMEOUT is not handled properly in the renderer process, and the timeout
// argument used in JS never comes all the way to the browser process.
// Let's just treat it like any other error where the position is unavailable.
- newPos.error_code = device::mojom::Geoposition::ErrorCode::POSITION_UNAVAILABLE;
+ newError->error_code = device::mojom::GeopositionErrorCode::kPositionUnavailable;
break;
case QGeoPositionInfoSource::ClosedError:
case QGeoPositionInfoSource::UnknownSourceError: // position unavailable is as good as it gets in Geoposition
default:
- newPos.error_code = device::mojom::Geoposition::ErrorCode::POSITION_UNAVAILABLE;
+ newError->error_code = device::mojom::GeopositionErrorCode::kPositionUnavailable;
break;
}
+ auto newResult = device::mojom::GeopositionResult::NewError(std::move(newError));
if (m_locationProvider)
- postToLocationProvider(base::BindOnce(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), newPos));
+ postToLocationProvider(base::BindOnce(&LocationProviderQt::updatePosition, m_locationProviderFactory.GetWeakPtr(), std::move(newResult)));
}
inline void QtPositioningHelper::postToLocationProvider(base::OnceClosure task)
@@ -226,10 +265,10 @@ void LocationProviderQt::SetUpdateCallback(const LocationProviderUpdateCallback&
m_callback = callback;
}
-void LocationProviderQt::updatePosition(const device::mojom::Geoposition &position)
+void LocationProviderQt::updatePosition(device::mojom::GeopositionResultPtr position)
{
- m_lastKnownPosition = position;
- m_callback.Run(this, position);
+ m_lastKnownPosition = std::move(position);
+ m_callback.Run(this, m_lastKnownPosition.Clone());
}
} // namespace QtWebEngineCore
diff --git a/src/core/location_provider_qt.h b/src/core/location_provider_qt.h
index bd1391586..93e409d77 100644
--- a/src/core/location_provider_qt.h
+++ b/src/core/location_provider_qt.h
@@ -4,7 +4,7 @@
#ifndef LOCATION_PROVIDER_QT_H
#define LOCATION_PROVIDER_QT_H
-#include <QtCore/qcompilerdetection.h>
+#include <QtCore/qtconfigmacros.h>
#include "services/device/public/cpp/geolocation/geoposition.h"
#include "services/device/public/cpp/geolocation/location_provider.h"
@@ -23,16 +23,17 @@ public:
// LocationProvider
void StartProvider(bool high_accuracy) override;
void StopProvider() override;
- const device::mojom::Geoposition& GetPosition() override { return m_lastKnownPosition; }
+ const device::mojom::GeopositionResult* GetPosition() override { return m_lastKnownPosition.get(); }
void OnPermissionGranted() override;
- void SetUpdateCallback(const LocationProviderUpdateCallback& callback) override;
+ void SetUpdateCallback(const LocationProviderUpdateCallback &callback) override;
+ void FillDiagnostics(device::mojom::GeolocationDiagnostics &) override {}
private:
friend class QtPositioningHelper;
- void updatePosition(const device::mojom::Geoposition &);
+ void updatePosition(device::mojom::GeopositionResultPtr);
- device::mojom::Geoposition m_lastKnownPosition;
+ device::mojom::GeopositionResultPtr m_lastKnownPosition;
LocationProviderUpdateCallback m_callback;
QtPositioningHelper *m_positioningHelper;
};
diff --git a/src/core/login_delegate_qt.cpp b/src/core/login_delegate_qt.cpp
index 140335735..3f916b797 100644
--- a/src/core/login_delegate_qt.cpp
+++ b/src/core/login_delegate_qt.cpp
@@ -11,22 +11,11 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
-#include "extensions/buildflags/buildflags.h"
-#include "services/network/public/cpp/features.h"
-
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "extensions/browser/info_map.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/manifest_handlers/mime_types_handler.h"
-#endif // BUILDFLAG(ENABLE_EXTENSIONS)
-
#include "net/url_request/url_request.h"
+#include "services/network/public/cpp/features.h"
#include "authentication_dialog_controller.h"
#include "authentication_dialog_controller_p.h"
-#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "extensions/extension_system_qt.h"
-#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#include "type_conversion.h"
#include "web_contents_view_qt.h"
#include "web_engine_context.h"
diff --git a/src/core/macos_context_type_helper.h b/src/core/macos_context_type_helper.h
deleted file mode 100644
index 1a2b0ff61..000000000
--- a/src/core/macos_context_type_helper.h
+++ /dev/null
@@ -1,7 +0,0 @@
-// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#ifndef MACOS_CONTEXT_TYPE_HELPER_H_
-#define MACOS_CONTEXT_TYPE_HELPER_H_
-bool isCurrentContextSoftware();
-void* cglContext(NSOpenGLContext*);
-#endif // MACOS_CONTEXT_TYPE_HELPER_H_
diff --git a/src/core/macos_context_type_helper.mm b/src/core/macos_context_type_helper.mm
deleted file mode 100644
index 9bdd36085..000000000
--- a/src/core/macos_context_type_helper.mm
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#import <Foundation/Foundation.h>
-#import <AppKit/AppKit.h>
-
-#include "macos_context_type_helper.h"
-
-bool isCurrentContextSoftware()
-{
- int rendererID = 0;
- [NSOpenGLContext.currentContext getValues:&rendererID forParameter:NSOpenGLContextParameterCurrentRendererID];
- return (rendererID & kCGLRendererIDMatchingMask) == kCGLRendererGenericFloatID;
-}
-
-void* cglContext(NSOpenGLContext *nsOpenGLContext)
-{
- return [nsOpenGLContext CGLContextObj];
-}
diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp
index a6ac070af..6dc45c442 100644
--- a/src/core/media_capture_devices_dispatcher.cpp
+++ b/src/core/media_capture_devices_dispatcher.cpp
@@ -221,91 +221,6 @@ void getDevicesForDesktopCapture(const content::MediaStreamRequest &request,
}
}
-content::DesktopMediaID getDefaultScreenId()
-{
-#if QT_CONFIG(webengine_webrtc)
- // Source id patterns are different across platforms.
- // On Linux and macOS, the source ids are randomish numbers assigned by the OS.
- // On Windows, the screens are enumerated consecutively in increasing order from 0.
-
- // In order to provide a correct screen id, we query for the available screen ids, and
- // select the first one as the main display id.
-#if !defined(WEBRTC_USE_X11)
- // The code is based on the file
- // chrome/browser/media/webrtc/native_desktop_media_list.cc.
- webrtc::DesktopCaptureOptions options =
- webrtc::DesktopCaptureOptions::CreateDefault();
- options.set_disable_effects(false);
- std::unique_ptr<webrtc::DesktopCapturer> screen_capturer(
- webrtc::DesktopCapturer::CreateScreenCapturer(options));
-
- if (screen_capturer) {
- webrtc::DesktopCapturer::SourceList screens;
- if (screen_capturer->GetSourceList(&screens)) {
- if (screens.size() > 0) {
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, screens[0].id);
- }
- }
- }
-#else
- // This is a workaround to avoid thread issues with DesktopCapturer [1]. Unfortunately,
- // creating a DesktopCapturer is not thread safe on X11 due to the use of webrtc::XErrorTrap.
- // Can be removed if https://crbug.com/2022 and/or https://crbug.com/570852 are fixed.
- // The code is based on the file
- // third_party/webrtc/modules/desktop_capture/linux/screen_capturer_x11.cc.
- //
- // [1]: webrtc::InProcessVideoCaptureDeviceLauncher::DoStartDesktopCaptureOnDeviceThread
- Display *display = XOpenDisplay(nullptr);
- if (!display) {
- qWarning("Unable to open display.");
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
- }
-
- int randrEventBase = 0;
- int errorBaseIgnored = 0;
- if (!XRRQueryExtension(display, &randrEventBase, &errorBaseIgnored)) {
- qWarning("X server does not support XRandR.");
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
- }
-
- int majorVersion = 0;
- int minorVersion = 0;
- if (!XRRQueryVersion(display, &majorVersion, &minorVersion)) {
- qWarning("X server does not support XRandR.");
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
- }
-
- if (majorVersion < 1 || (majorVersion == 1 && minorVersion < 5)) {
- qWarning("XRandR entension is older than v1.5.");
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
- }
-
- typedef XRRMonitorInfo *(*GetMonitorsFunc)(Display *, Window, Bool, int *);
- GetMonitorsFunc getMonitors = reinterpret_cast<GetMonitorsFunc>(dlsym(RTLD_DEFAULT, "XRRGetMonitors"));
- typedef void (*FreeMonitorsFunc)(XRRMonitorInfo*);
- FreeMonitorsFunc freeMonitors = reinterpret_cast<FreeMonitorsFunc>(dlsym(RTLD_DEFAULT, "XRRFreeMonitors"));
- if (!getMonitors || !freeMonitors) {
- qWarning("Unable to link XRandR monitor functions.");
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
- }
-
- Window rootWindow = RootWindow(display, DefaultScreen(display));
- if (rootWindow == BadValue) {
- qWarning("Unable to get the root window.");
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
- }
-
- int numMonitors = 0;
- XRRMonitorInfo *monitors = getMonitors(display, rootWindow, true, &numMonitors);
- auto cleanup = qScopeGuard([&] () { freeMonitors(monitors); });
- if (numMonitors > 0)
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, monitors[0].name);
-#endif // !defined(WEBRTC_USE_X11)
-#endif // QT_CONFIG(webengine_webrtc)
-
- return content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0);
-}
-
WebContentsAdapterClient::MediaRequestFlags mediaRequestFlagsForRequest(const content::MediaStreamRequest &request)
{
if (request.audio_type == MediaStreamType::DEVICE_AUDIO_CAPTURE &&
@@ -389,13 +304,12 @@ private:
bool m_started = false;
base::RepeatingClosure m_onStop; // currently unused
};
-
} // namespace
-MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest(const content::MediaStreamRequest &request,
- content::MediaResponseCallback callback)
- : request(request)
- , callback(std::move(callback))
+MediaCaptureDevicesDispatcher::PendingAccessRequest::PendingAccessRequest(
+ const content::MediaStreamRequest &request, content::MediaResponseCallback callback,
+ content::DesktopMediaID id)
+ : request(request), callback(std::move(callback)), mediaId(id)
{
}
@@ -431,6 +345,8 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content:
bool desktopVideoRequested = finalFlags.testFlag(WebContentsAdapterClient::MediaDesktopVideoCapture);
if (securityOriginsMatch) {
+ content::DesktopMediaID &id = queue.front()->mediaId;
+
if (microphoneRequested || webcamRequested) {
switch (request.request_type) {
case blink::MEDIA_OPEN_DEVICE_PEPPER_ONLY:
@@ -444,11 +360,11 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content:
microphoneRequested, webcamRequested, deviceSet);
break;
}
- } else if (desktopVideoRequested) {
+ } else if (desktopVideoRequested && !id.is_null()) {
deviceSet.stream_devices.emplace_back(blink::mojom::StreamDevices::New());
bool captureAudio = desktopAudioRequested && m_loopbackAudioSupported;
blink::mojom::StreamDevices &stream_devices = *deviceSet.stream_devices[0];
- getDevicesForDesktopCapture(request, webContents, getDefaultScreenId(), captureAudio,
+ getDevicesForDesktopCapture(request, webContents, id, captureAudio,
request.disable_local_echo, stream_devices);
}
}
@@ -497,7 +413,9 @@ void MediaCaptureDevicesDispatcher::WebContentsDestroyed(content::WebContents *w
m_pendingRequests.erase(webContents);
}
-void MediaCaptureDevicesDispatcher::processMediaAccessRequest(content::WebContents *webContents, const content::MediaStreamRequest &request, content::MediaResponseCallback callback)
+void MediaCaptureDevicesDispatcher::processMediaAccessRequest(
+ content::WebContents *webContents, const content::MediaStreamRequest &request,
+ content::MediaResponseCallback callback, content::DesktopMediaID id)
{
DCHECK_CURRENTLY_ON(BrowserThread::UI);
// Ensure we are observing the deletion of |webContents|.
@@ -516,7 +434,7 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(content::WebConten
const bool screenCaptureEnabled = adapterClient->webEngineSettings()->testAttribute(
QWebEngineSettings::ScreenCaptureEnabled);
const bool originIsSecure = network::IsUrlPotentiallyTrustworthy(request.security_origin);
- if (!screenCaptureEnabled || !originIsSecure) {
+ if (!screenCaptureEnabled || !originIsSecure || (id.is_null() && request.requested_video_device_id.empty())) {
std::move(callback).Run(blink::mojom::StreamDevicesSet(), MediaStreamRequestResult::INVALID_STATE, std::unique_ptr<content::MediaStreamUI>());
return;
}
@@ -528,7 +446,7 @@ void MediaCaptureDevicesDispatcher::processMediaAccessRequest(content::WebConten
}
}
- enqueueMediaAccessRequest(webContents, request, std::move(callback));
+ enqueueMediaAccessRequest(webContents, request, std::move(callback), id);
// We might not require this approval for pepper requests.
adapterClient->runMediaAccessPermissionRequest(toQt(request.security_origin), flags);
}
@@ -543,13 +461,11 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content::
content::DesktopMediaID mediaId;
if (main_frame) {
- // The extension name that the stream is registered with.
- std::string originalExtensionName;
// Resolve DesktopMediaID for the specified device id.
mediaId = content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
request.requested_video_device_id, main_frame->GetProcess()->GetID(),
main_frame->GetRoutingID(), url::Origin::Create(request.security_origin),
- &originalExtensionName, content::kRegistryStreamTypeDesktop);
+ content::kRegistryStreamTypeDesktop);
}
// Received invalid device id.
@@ -576,14 +492,14 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content::
std::make_unique<MediaStreamUIQt>(webContents, *deviceSet.stream_devices[0]));
}
-void MediaCaptureDevicesDispatcher::enqueueMediaAccessRequest(content::WebContents *webContents,
- const content::MediaStreamRequest &request,
- content::MediaResponseCallback callback)
+void MediaCaptureDevicesDispatcher::enqueueMediaAccessRequest(
+ content::WebContents *webContents, const content::MediaStreamRequest &request,
+ content::MediaResponseCallback callback, content::DesktopMediaID id)
{
DCHECK_CURRENTLY_ON(BrowserThread::UI);
RequestsQueue &queue = m_pendingRequests[webContents];
- queue.push_back(std::make_unique<PendingAccessRequest>(request, std::move(callback)));
+ queue.push_back(std::make_unique<PendingAccessRequest>(request, std::move(callback), id));
}
void MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest(content::WebContents *webContents)
diff --git a/src/core/media_capture_devices_dispatcher.h b/src/core/media_capture_devices_dispatcher.h
index 37f41901b..2b6bb98d8 100644
--- a/src/core/media_capture_devices_dispatcher.h
+++ b/src/core/media_capture_devices_dispatcher.h
@@ -24,7 +24,8 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver,
public:
static MediaCaptureDevicesDispatcher *GetInstance();
- void processMediaAccessRequest(content::WebContents *, const content::MediaStreamRequest &, content::MediaResponseCallback);
+ void processMediaAccessRequest(content::WebContents *, const content::MediaStreamRequest &,
+ content::MediaResponseCallback, content::DesktopMediaID);
// Called back from our WebContentsAdapter to grant the requested permission.
void handleMediaAccessPermissionResponse(content::WebContents *, const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags);
@@ -52,11 +53,13 @@ private:
friend struct base::DefaultSingletonTraits<MediaCaptureDevicesDispatcher>;
struct PendingAccessRequest {
- PendingAccessRequest(const content::MediaStreamRequest &request, content::MediaResponseCallback callback);
+ PendingAccessRequest(const content::MediaStreamRequest &request,
+ content::MediaResponseCallback callback, content::DesktopMediaID id);
~PendingAccessRequest();
content::MediaStreamRequest request;
content::MediaResponseCallback callback;
+ content::DesktopMediaID mediaId;
};
typedef base::circular_deque<std::unique_ptr<PendingAccessRequest>> RequestsQueue;
typedef base::flat_map<content::WebContents *, RequestsQueue> RequestsQueues;
@@ -68,8 +71,10 @@ private:
void WebContentsDestroyed(content::WebContents *webContents) override;
// Helpers for ProcessMediaAccessRequest().
+ void handleRequest(content::WebContents *, const content::MediaStreamRequest &, content::MediaResponseCallback);
void processDesktopCaptureAccessRequest(content::WebContents *, const content::MediaStreamRequest &, content::MediaResponseCallback);
- void enqueueMediaAccessRequest(content::WebContents *, const content::MediaStreamRequest &, content::MediaResponseCallback);
+ void enqueueMediaAccessRequest(content::WebContents *, const content::MediaStreamRequest &,
+ content::MediaResponseCallback, content::DesktopMediaID);
void ProcessQueuedAccessRequest(content::WebContents *);
// Called by the MediaObserver() functions, executed on UI thread.
diff --git a/src/core/native_web_keyboard_event_qt.cpp b/src/core/native_web_keyboard_event_qt.cpp
index 4755c60bf..9a5576fbb 100644
--- a/src/core/native_web_keyboard_event_qt.cpp
+++ b/src/core/native_web_keyboard_event_qt.cpp
@@ -1,64 +1,77 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE.Chromium file.
-#include "content/public/browser/native_web_keyboard_event.h"
-#include <QKeyEvent>
+#include <QtCore/qglobal.h>
-namespace {
+#if !defined(Q_OS_MACOS)
+#include "native_web_keyboard_event_qt.h"
+
+#include <QtGui/QKeyEvent>
+
+namespace QtWebEngineCore {
+gfx::NativeEvent ToNativeEvent(QKeyEvent *keyEvent)
+{
+ return reinterpret_cast<gfx::NativeEvent>(keyEvent);
+}
+QKeyEvent *ToKeyEvent(gfx::NativeEvent nativeEvent)
+{
+ return reinterpret_cast<QKeyEvent *>(nativeEvent);
+}
+} // namespace QtWebEngineCore
+
+namespace {
// We need to copy |os_event| in NativeWebKeyboardEvent because it is
// queued in RenderWidgetHost and may be passed and used
// RenderViewHostDelegate::HandledKeybardEvent after the original aura
// event is destroyed.
-gfx::NativeEvent CopyEvent(gfx::NativeEvent event)
+gfx::NativeEvent CopyEvent(gfx::NativeEvent nativeEvent)
{
- if (!event)
+ if (!nativeEvent)
return nullptr;
- QKeyEvent *keyEvent = reinterpret_cast<QKeyEvent *>(event);
- return reinterpret_cast<gfx::NativeEvent>(keyEvent->clone());
+ QKeyEvent *keyEvent = QtWebEngineCore::ToKeyEvent(nativeEvent);
+ return QtWebEngineCore::ToNativeEvent(keyEvent->clone());
}
-void DestroyEvent(gfx::NativeEvent event)
+void DestroyEvent(gfx::NativeEvent nativeEvent)
{
- delete reinterpret_cast<QKeyEvent*>(event);
+ delete QtWebEngineCore::ToKeyEvent(nativeEvent);
}
+} // namespace
-} // namespace
-
-using blink::WebKeyboardEvent;
namespace content {
NativeWebKeyboardEvent::NativeWebKeyboardEvent(const blink::WebKeyboardEvent &web_event, gfx::NativeView)
- : WebKeyboardEvent(web_event)
+ : blink::WebKeyboardEvent(web_event)
, os_event(nullptr)
- , skip_in_browser(false)
+ , skip_if_unhandled(false)
{
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type type, int modifiers,
base::TimeTicks timestamp)
- : WebKeyboardEvent(type, modifiers, timestamp)
+ : blink::WebKeyboardEvent(type, modifiers, timestamp)
, os_event(nullptr)
- , skip_in_browser(false)
+ , skip_if_unhandled(false)
{
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event)
: os_event(CopyEvent(native_event))
- , skip_in_browser(false)
+ , skip_if_unhandled(false)
{
}
NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& other)
- : WebKeyboardEvent(other)
+ : blink::WebKeyboardEvent(other)
, os_event(CopyEvent(other.os_event))
- , skip_in_browser(other.skip_in_browser)
+ , skip_if_unhandled(other.skip_if_unhandled)
{
}
@@ -66,10 +79,10 @@ NativeWebKeyboardEvent &NativeWebKeyboardEvent::operator=(const NativeWebKeyboar
{
if (this == &other)
return *this;
- WebKeyboardEvent::operator=(other);
+ blink::WebKeyboardEvent::operator=(other);
DestroyEvent(os_event);
os_event = CopyEvent(other.os_event);
- skip_in_browser = other.skip_in_browser;
+ skip_if_unhandled = other.skip_if_unhandled;
return *this;
}
@@ -78,3 +91,4 @@ NativeWebKeyboardEvent::~NativeWebKeyboardEvent() {
}
} // namespace content
+#endif // !defined(Q_OS_MACOS)
diff --git a/src/core/native_web_keyboard_event_qt.h b/src/core/native_web_keyboard_event_qt.h
new file mode 100644
index 000000000..13179d07a
--- /dev/null
+++ b/src/core/native_web_keyboard_event_qt.h
@@ -0,0 +1,20 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef NATIVE_WEB_KEYBOARD_EVENT_QT_H
+#define NATIVE_WEB_KEYBOARD_EVENT_QT_H
+
+#include <QtCore/qglobal.h>
+
+#include "content/public/common/input/native_web_keyboard_event.h"
+
+QT_FORWARD_DECLARE_CLASS(QKeyEvent)
+
+namespace QtWebEngineCore {
+
+gfx::NativeEvent ToNativeEvent(QKeyEvent *keyEvent);
+QKeyEvent *ToKeyEvent(gfx::NativeEvent event);
+
+} // namespace QtWebEngineCore
+
+#endif // NATIVE_WEB_KEYBOARD_EVENT_QT_H
diff --git a/src/core/native_web_keyboard_event_qt_mac.mm b/src/core/native_web_keyboard_event_qt_mac.mm
new file mode 100644
index 000000000..0f5b12db4
--- /dev/null
+++ b/src/core/native_web_keyboard_event_qt_mac.mm
@@ -0,0 +1,155 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// Copyright 2011 The Chromium Authors
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.Chromium file.
+
+// This is a workaround to be able to include Qt headers without
+// "redefinition of 'NSString' as different kind of symbol" errors.
+// TODO: Remove this when namespace ambiguity issues are fixed properly,
+// see get_forward_declaration_macro() in cmake/Functions.cmake
+#undef Q_FORWARD_DECLARE_OBJC_CLASS
+
+#include "native_web_keyboard_event_qt.h"
+
+#include <AppKit/AppKit.h>
+
+#include "base/apple/owned_objc.h"
+
+#include <QtGui/QKeyEvent>
+#include <QtGui/private/qapplekeymapper_p.h>
+
+namespace QtWebEngineCore {
+
+base::apple::OwnedNSEvent ToNativeEvent(QKeyEvent *keyEvent)
+{
+ NSEventType type;
+ switch (keyEvent->type()) {
+ case QEvent::KeyPress:
+ type = NSEventTypeKeyDown;
+ break;
+ case QEvent::KeyRelease:
+ type = NSEventTypeKeyUp;
+ break;
+ default:
+ Q_UNREACHABLE();
+ return base::apple::OwnedNSEvent();
+ }
+
+ NSString *text = keyEvent->text().toNSString();
+ if (text.length == 0) {
+ Qt::Key key = static_cast<Qt::Key>(keyEvent->key());
+ QChar cocoaKey = QAppleKeyMapper::toCocoaKey(key);
+ text = QStringView(&cocoaKey, 1).toNSString();
+ }
+
+ return base::apple::OwnedNSEvent([NSEvent
+ keyEventWithType:type
+ location:NSZeroPoint
+ modifierFlags:QAppleKeyMapper::toCocoaModifiers(keyEvent->modifiers())
+ timestamp:keyEvent->timestamp() / 1000
+ windowNumber:0
+ context:nil
+ characters:text
+ charactersIgnoringModifiers:text
+ isARepeat:keyEvent->isAutoRepeat()
+ keyCode:keyEvent->nativeVirtualKey()
+ ]);
+}
+
+// Based on qtbase/src/plugins/platforms/cocoa/qnsview_keys.mm (KeyEvent::KeyEvent())
+QKeyEvent *ToKeyEvent(base::apple::OwnedNSEvent event)
+{
+ NSEvent *nsevent = event.Get();
+
+ QEvent::Type type = QEvent::None;
+ switch (nsevent.type) {
+ case NSEventTypeKeyDown:
+ type = QEvent::KeyPress;
+ break;
+ case NSEventTypeKeyUp:
+ type = QEvent::KeyRelease;
+ break;
+ default:
+ Q_UNREACHABLE();
+ return nullptr;
+ }
+
+ // Scan codes are hardware dependent codes for each key. There is no way to get these
+ // from Carbon or Cocoa, so leave it 0, as documented in QKeyEvent::nativeScanCode().
+ quint32 nativeScanCode = 0;
+ quint32 nativeVirtualKey = nsevent.keyCode;
+
+ NSEventModifierFlags nativeModifiers = nsevent.modifierFlags;
+ Qt::KeyboardModifiers modifiers = QAppleKeyMapper::fromCocoaModifiers(nativeModifiers);
+
+ NSString *charactersIgnoringModifiers = nsevent.charactersIgnoringModifiers;
+ NSString *characters = nsevent.characters;
+
+ // If a dead key occurs as a result of pressing a key combination then
+ // characters will have 0 length, but charactersIgnoringModifiers will
+ // have a valid character in it. This enables key combinations such as
+ // ALT+E to be used as a shortcut with an English keyboard even though
+ // pressing ALT+E will give a dead key while doing normal text input.
+ Qt::Key key = Qt::Key_unknown;
+ if (characters.length || charactersIgnoringModifiers.length) {
+ QChar character = QChar::ReplacementCharacter;
+ if (nativeModifiers & (NSEventModifierFlagControl | NSEventModifierFlagOption)
+ && charactersIgnoringModifiers.length)
+ character = QChar([charactersIgnoringModifiers characterAtIndex:0]);
+ else if (characters.length)
+ character = QChar([characters characterAtIndex:0]);
+ key = QAppleKeyMapper::fromCocoaKey(character);
+ }
+
+ QString text = QString::fromNSString(characters);
+ bool autorep = nsevent.ARepeat;
+
+ return new QKeyEvent(type, key, modifiers, nativeScanCode, nativeVirtualKey, nativeModifiers,
+ text, autorep);
+}
+
+} // namespace QtWebEngineCore
+
+namespace content {
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(const blink::WebKeyboardEvent &web_event, gfx::NativeView)
+ : blink::WebKeyboardEvent(web_event)
+ , skip_if_unhandled(false)
+{
+}
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(blink::WebInputEvent::Type type, int modifiers,
+ base::TimeTicks timestamp)
+ : blink::WebKeyboardEvent(type, modifiers, timestamp)
+ , skip_if_unhandled(false)
+{
+}
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(gfx::NativeEvent native_event)
+ : os_event(native_event) // FIXME: Copy?
+ , skip_if_unhandled(false)
+{
+}
+
+NativeWebKeyboardEvent::NativeWebKeyboardEvent(const NativeWebKeyboardEvent& other)
+ : blink::WebKeyboardEvent(other)
+ , os_event(other.os_event) // FIXME: Copy?
+ , skip_if_unhandled(other.skip_if_unhandled)
+{
+}
+
+NativeWebKeyboardEvent &NativeWebKeyboardEvent::operator=(const NativeWebKeyboardEvent &other)
+{
+ blink::WebKeyboardEvent::operator=(other);
+
+ os_event = other.os_event; // FIXME: Copy?
+ skip_if_unhandled = other.skip_if_unhandled;
+
+ return *this;
+}
+
+NativeWebKeyboardEvent::~NativeWebKeyboardEvent() = default;
+
+} // namespace content
diff --git a/src/core/net/client_cert_qt.cpp b/src/core/net/client_cert_qt.cpp
index d5ea1a776..044e5618e 100644
--- a/src/core/net/client_cert_qt.cpp
+++ b/src/core/net/client_cert_qt.cpp
@@ -3,8 +3,9 @@
#include "client_cert_qt.h"
-#include "base/bind.h"
-#include "base/callback_forward.h"
+#include "base/functional/bind.h"
+#include "base/functional/callback_forward.h"
+#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browser_task_traits.h"
#include "crypto/crypto_buildflags.h"
#include "net/ssl/client_cert_store.h"
@@ -16,7 +17,6 @@
#include "third_party/boringssl/src/include/openssl/evp.h"
#include "client_cert_store_data.h"
-#include "profile_io_data_qt.h"
#include <QtNetwork/qtnetworkglobal.h>
diff --git a/src/core/net/client_cert_qt.h b/src/core/net/client_cert_qt.h
index 85b0d28be..96579fae6 100644
--- a/src/core/net/client_cert_qt.h
+++ b/src/core/net/client_cert_qt.h
@@ -4,9 +4,9 @@
#ifndef CLIENT_CERT_QT_P_H
#define CLIENT_CERT_QT_P_H
-#include "net/ssl/client_cert_store.h"
-#include "base/callback_forward.h"
+#include "base/functional/callback_forward.h"
#include "net/cert/x509_certificate.h"
+#include "net/ssl/client_cert_store.h"
namespace net {
class SSLCertRequestInfo;
diff --git a/src/core/net/client_cert_store_data.cpp b/src/core/net/client_cert_store_data.cpp
index 306e782e0..0de6885df 100644
--- a/src/core/net/client_cert_store_data.cpp
+++ b/src/core/net/client_cert_store_data.cpp
@@ -97,7 +97,8 @@ void ClientCertificateStoreData::add(const QSslCertificate &certificate, const Q
Entry *data = new Entry;
data->keyPtr = wrapOpenSSLPrivateKey(sslKeyInBytes);
- data->certPtr = net::X509Certificate::CreateFromBytes(base::make_span((const unsigned char *)certInBytes.data(), certInBytes.length()));
+ data->certPtr = net::X509Certificate::CreateFromBytes(base::make_span((const unsigned char *)certInBytes.data(),
+ (unsigned long)certInBytes.length()));
data->key = privateKey;
data->certificate = certificate;
extraCerts.append(data);
diff --git a/src/core/net/cookie_monster_delegate_qt.cpp b/src/core/net/cookie_monster_delegate_qt.cpp
index dc47de207..d107c520c 100644
--- a/src/core/net/cookie_monster_delegate_qt.cpp
+++ b/src/core/net/cookie_monster_delegate_qt.cpp
@@ -3,7 +3,7 @@
#include "cookie_monster_delegate_qt.h"
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "net/cookies/cookie_util.h"
#include "services/network/public/mojom/cookie_manager.mojom.h"
@@ -97,8 +97,9 @@ void CookieMonsterDelegateQt::setCookie(const QNetworkCookie &cookie, const QUrl
std::string cookie_line = cookie.toRawForm().toStdString();
net::CookieInclusionStatus inclusion;
- auto canonCookie = net::CanonicalCookie::Create(gurl, cookie_line, base::Time::Now(), absl::nullopt, absl::nullopt, &inclusion);
- if (!inclusion.IsInclude()) {
+ auto canonCookie = net::CanonicalCookie::Create(gurl, cookie_line, base::Time::Now(),
+ absl::nullopt, absl::nullopt, true, &inclusion);
+ if (!canonCookie || !inclusion.IsInclude()) {
LOG(WARNING) << "QWebEngineCookieStore::setCookie() - Tried to set invalid cookie";
return;
}
diff --git a/src/core/net/cookie_monster_delegate_qt.h b/src/core/net/cookie_monster_delegate_qt.h
index 4273e96ef..f6872323d 100644
--- a/src/core/net/cookie_monster_delegate_qt.h
+++ b/src/core/net/cookie_monster_delegate_qt.h
@@ -42,7 +42,7 @@ namespace QtWebEngineCore {
class CookieMonsterDelegateQtPrivate;
-class Q_WEBENGINECORE_PRIVATE_EXPORT CookieMonsterDelegateQt : public base::RefCountedThreadSafe<CookieMonsterDelegateQt>
+class Q_WEBENGINECORE_EXPORT CookieMonsterDelegateQt : public base::RefCountedThreadSafe<CookieMonsterDelegateQt>
{
QPointer<QWebEngineCookieStore> m_client;
std::vector<std::unique_ptr<net::CookieChangeSubscription>> m_subscriptions;
diff --git a/src/core/net/custom_url_loader_factory.cpp b/src/core/net/custom_url_loader_factory.cpp
index bd19aa436..4274def99 100644
--- a/src/core/net/custom_url_loader_factory.cpp
+++ b/src/core/net/custom_url_loader_factory.cpp
@@ -32,6 +32,7 @@
#include <QtCore/qiodevice.h>
#include <QtCore/qmimedatabase.h>
#include <QtCore/qmimedata.h>
+#include <QtCore/qpointer.h>
#include <QtCore/qurl.h>
namespace QtWebEngineCore {
@@ -150,9 +151,11 @@ private:
m_firstBytePosition = m_byteRange.first_byte_position();
// m_taskRunner->PostTask(FROM_HERE,
- content::GetUIThreadTaskRunner({})->PostTask(FROM_HERE,
- base::BindOnce(&URLRequestCustomJobProxy::initialize, m_proxy,
- m_request.url, m_request.method, m_request.request_initiator, std::move(headers)));
+ content::GetUIThreadTaskRunner({})->PostTask(
+ FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::initialize, m_proxy, m_request.url,
+ m_request.method, m_request.request_initiator, std::move(headers),
+ m_request.request_body));
}
void CompleteWithFailure(network::CorsErrorStatus cors_error)
@@ -271,7 +274,8 @@ private:
m_head->encoded_data_length = m_head->headers->raw_headers().length();
if (!m_redirect.is_empty()) {
- m_head->content_length = m_head->encoded_body_length = -1;
+ m_head->content_length = {};
+ m_head->encoded_body_length = {};
net::RedirectInfo::FirstPartyURLPolicy first_party_url_policy =
m_request.update_first_party_url_on_redirect ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT
: net::RedirectInfo::FirstPartyURLPolicy::NEVER_CHANGE_URL;
@@ -339,7 +343,8 @@ private:
}
m_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(net::HttpUtil::AssembleRawHeaders(headers));
m_head->encoded_data_length = m_head->headers->raw_headers().length();
- m_head->content_length = m_head->encoded_body_length = -1;
+ m_head->content_length = {};
+ m_head->encoded_body_length = {};
m_client->OnReceiveResponse(std::move(m_head), mojo::ScopedDataPipeConsumerHandle(), absl::nullopt);
CompleteWithFailure(net::Error(error));
}
diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
index f61fb704a..159fa28ca 100644
--- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
+++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
@@ -8,8 +8,8 @@
#include "plugin_response_interceptor_url_loader_throttle.h"
-#include "base/bind.h"
-#include "base/guid.h"
+#include "base/functional/bind.h"
+#include "base/uuid.h"
#include "chrome/browser/extensions/api/streams_private/streams_private_api.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
@@ -86,13 +86,16 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL
bool *defer)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (content::download_utils::MustDownload(response_url, response_head->headers.get(), response_head->mime_type))
- return;
content::WebContents *web_contents = content::WebContents::FromFrameTreeNodeId(m_frame_tree_node_id);
if (!web_contents)
return;
+ if (content::download_utils::MustDownload(
+ web_contents->GetBrowserContext(),
+ response_url, response_head->headers.get(), response_head->mime_type))
+ return;
+
std::string extension_id;
if (response_head->mime_type == "application/pdf")
extension_id = extension_misc::kPdfExtensionId;
@@ -120,7 +123,7 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL
MimeTypesHandler::ReportUsedHandler(extension_id);
- std::string view_id = base::GenerateGUID();
+ std::string view_id = base::Uuid::GenerateRandomV4().AsLowercaseString();
// The string passed down to the original client with the response body.
std::string payload = view_id;
@@ -173,7 +176,7 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL
auto transferrable_loader = blink::mojom::TransferrableURLLoader::New();
transferrable_loader->url = GURL(
extensions::Extension::GetBaseURLFromExtensionId(extension_id).spec() +
- base::GenerateGUID());
+ base::Uuid::GenerateRandomV4().AsLowercaseString());
transferrable_loader->url_loader = std::move(original_loader);
transferrable_loader->url_loader_client = std::move(original_client);
transferrable_loader->head = std::move(deep_copied_response);
diff --git a/src/core/net/proxy_config_service_qt.cpp b/src/core/net/proxy_config_service_qt.cpp
index 70bcb59b4..fcce08550 100644
--- a/src/core/net/proxy_config_service_qt.cpp
+++ b/src/core/net/proxy_config_service_qt.cpp
@@ -16,14 +16,15 @@
net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qtProxy)
{
- net::HostPortPair hostPortPair(qtProxy.hostName().toStdString(), qtProxy.port());
+ std::string host = qtProxy.hostName().toStdString();
+ uint16_t port = qtProxy.port();
switch (qtProxy.type()) {
case QNetworkProxy::Socks5Proxy:
- return net::ProxyServer(net::ProxyServer::SCHEME_SOCKS5, hostPortPair);
+ return net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_SOCKS5, host, port);
case QNetworkProxy::HttpProxy:
case QNetworkProxy::HttpCachingProxy:
case QNetworkProxy::FtpCachingProxy:
- return net::ProxyServer(net::ProxyServer::SCHEME_HTTP, hostPortPair);
+ return net::ProxyServer::FromSchemeHostAndPort(net::ProxyServer::SCHEME_HTTP, host, port);
case QNetworkProxy::NoProxy:
case QNetworkProxy::DefaultProxy:
return net::ProxyServer(net::ProxyServer::SCHEME_DIRECT, net::HostPortPair());
diff --git a/src/core/net/proxying_restricted_cookie_manager_qt.cpp b/src/core/net/proxying_restricted_cookie_manager_qt.cpp
index 8608d35cd..d4d5cc4ab 100644
--- a/src/core/net/proxying_restricted_cookie_manager_qt.cpp
+++ b/src/core/net/proxying_restricted_cookie_manager_qt.cpp
@@ -10,8 +10,7 @@
#include "api/qwebenginecookiestore.h"
#include "api/qwebenginecookiestore_p.h"
-#include "profile_adapter.h"
-#include "profile_qt.h"
+#include "profile_io_data_qt.h"
#include "type_conversion.h"
#include "base/memory/ptr_util.h"
@@ -66,16 +65,15 @@ ProxyingRestrictedCookieManagerQt::~ProxyingRestrictedCookieManagerQt()
void ProxyingRestrictedCookieManagerQt::GetAllForUrl(const GURL &url,
const net::SiteForCookies &site_for_cookies,
- const url::Origin &top_frame_origin,
+ const url::Origin &top_frame_origin, bool has_storage_access,
network::mojom::CookieManagerGetOptionsPtr options,
- bool partitioned_cookies_runtime_feature_enabled,
GetAllForUrlCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (allowCookies(url, site_for_cookies)) {
- underlying_restricted_cookie_manager_->GetAllForUrl(url, site_for_cookies, top_frame_origin, std::move(options),
- partitioned_cookies_runtime_feature_enabled, std::move(callback));
+ underlying_restricted_cookie_manager_->GetAllForUrl(url, site_for_cookies, top_frame_origin, has_storage_access,
+ std::move(options), std::move(callback));
} else {
std::move(callback).Run(std::vector<net::CookieWithAccessResult>());
}
@@ -85,13 +83,15 @@ void ProxyingRestrictedCookieManagerQt::SetCanonicalCookie(const net::CanonicalC
const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
net::CookieInclusionStatus status,
SetCanonicalCookieCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (allowCookies(url, site_for_cookies)) {
- underlying_restricted_cookie_manager_->SetCanonicalCookie(cookie, url, site_for_cookies, top_frame_origin, status, std::move(callback));
+ underlying_restricted_cookie_manager_->SetCanonicalCookie(cookie, url, site_for_cookies, top_frame_origin,
+ has_storage_access, status, std::move(callback));
} else {
std::move(callback).Run(false);
}
@@ -100,25 +100,26 @@ void ProxyingRestrictedCookieManagerQt::SetCanonicalCookie(const net::CanonicalC
void ProxyingRestrictedCookieManagerQt::AddChangeListener(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
mojo::PendingRemote<network::mojom::CookieChangeListener> listener,
AddChangeListenerCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- underlying_restricted_cookie_manager_->AddChangeListener(url, site_for_cookies, top_frame_origin, std::move(listener), std::move(callback));
+ underlying_restricted_cookie_manager_->AddChangeListener(url, site_for_cookies, top_frame_origin, has_storage_access,
+ std::move(listener), std::move(callback));
}
void ProxyingRestrictedCookieManagerQt::SetCookieFromString(const GURL &url,
const net::SiteForCookies &site_for_cookies,
- const url::Origin &top_frame_origin,
+ const url::Origin &top_frame_origin, bool has_storage_access,
const std::string &cookie,
- bool partitioned_cookies_runtime_feature_enabled,
SetCookieFromStringCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (allowCookies(url, site_for_cookies)) {
- underlying_restricted_cookie_manager_->SetCookieFromString(url, site_for_cookies, top_frame_origin, cookie,
- partitioned_cookies_runtime_feature_enabled, std::move(callback));
+ underlying_restricted_cookie_manager_->SetCookieFromString(url, site_for_cookies, top_frame_origin, has_storage_access,
+ cookie, std::move(callback));
} else {
std::move(callback).Run(false, false); // FIXME: is true, true in aw_proxying_restricted_cookie_manager.cc though..
}
@@ -127,33 +128,30 @@ void ProxyingRestrictedCookieManagerQt::SetCookieFromString(const GURL &url,
void ProxyingRestrictedCookieManagerQt::GetCookiesString(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
- bool partitioned_cookies_runtime_feature_enabled,
+ bool has_storage_access, bool get_version_shared_memory,
GetCookiesStringCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (allowCookies(url, site_for_cookies)) {
underlying_restricted_cookie_manager_->GetCookiesString(url, site_for_cookies, top_frame_origin,
- partitioned_cookies_runtime_feature_enabled, std::move(callback));
+ has_storage_access, get_version_shared_memory,
+ std::move(callback));
} else {
- std::move(callback).Run("");
+ std::move(callback).Run(network::mojom::kInvalidCookieVersion, base::ReadOnlySharedMemoryRegion(), "");
}
}
void ProxyingRestrictedCookieManagerQt::CookiesEnabledFor(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin & /*top_frame_origin*/,
+ bool /*has_storage_access*/,
CookiesEnabledForCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
std::move(callback).Run(allowCookies(url, site_for_cookies));
}
-void ProxyingRestrictedCookieManagerQt::ConvertPartitionedCookiesToUnpartitioned(const GURL&)
-{
- NOTIMPLEMENTED();
-}
-
bool ProxyingRestrictedCookieManagerQt::allowCookies(const GURL &url, const net::SiteForCookies &site_for_cookies) const
{
if (!m_profileIoData)
diff --git a/src/core/net/proxying_restricted_cookie_manager_qt.h b/src/core/net/proxying_restricted_cookie_manager_qt.h
index 95e193f76..faf0545c3 100644
--- a/src/core/net/proxying_restricted_cookie_manager_qt.h
+++ b/src/core/net/proxying_restricted_cookie_manager_qt.h
@@ -27,36 +27,39 @@ public:
void GetAllForUrl(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
network::mojom::CookieManagerGetOptionsPtr options,
- bool partitioned_cookies_runtime_feature_enabled,
GetAllForUrlCallback callback) override;
+
void SetCanonicalCookie(const net::CanonicalCookie& cookie,
const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
net::CookieInclusionStatus status,
SetCanonicalCookieCallback callback) override;
void AddChangeListener(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
mojo::PendingRemote<network::mojom::CookieChangeListener> listener,
AddChangeListenerCallback callback) override;
void SetCookieFromString(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
const std::string &cookie,
- bool partitioned_cookies_runtime_feature_enabled,
SetCookieFromStringCallback callback) override;
void GetCookiesString(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
- bool partitioned_cookies_runtime_feature_enabled,
+ bool has_storage_access, bool get_version_shared_memory,
GetCookiesStringCallback callback) override;
void CookiesEnabledFor(const GURL &url,
const net::SiteForCookies &site_for_cookies,
const url::Origin &top_frame_origin,
+ bool has_storage_access,
CookiesEnabledForCallback callback) override;
- void ConvertPartitionedCookiesToUnpartitioned(const GURL&) override;
// Internal:
bool allowCookies(const GURL &url, const net::SiteForCookies &site_for_cookies) const;
diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp
index 70ec61b34..3a83ed7ea 100644
--- a/src/core/net/proxying_url_loader_factory_qt.cpp
+++ b/src/core/net/proxying_url_loader_factory_qt.cpp
@@ -5,7 +5,7 @@
#include <utility>
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "content/browser/web_contents/web_contents_impl.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
@@ -24,6 +24,7 @@
#include "web_contents_adapter.h"
#include "web_contents_adapter_client.h"
#include "web_contents_view_qt.h"
+#include "net/resource_request_body_qt.h"
// originally based on aw_proxying_url_loader_factory.cc:
// Copyright 2018 The Chromium Authors. All rights reserved.
@@ -126,8 +127,6 @@ public:
void PauseReadingBodyFromNet() override;
void ResumeReadingBodyFromNet() override;
- static inline void cleanup(QWebEngineUrlRequestInfo *info) { delete info; }
-
private:
void InterceptOnUIThread();
void ContinueAfterIntercept();
@@ -165,11 +164,18 @@ private:
// error didn't occur.
int error_status_ = net::OK;
network::ResourceRequest request_;
+ ResourceRequestBody request_body_;
network::mojom::URLResponseHeadPtr current_response_;
const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
- QScopedPointer<QWebEngineUrlRequestInfo, InterceptedRequest> request_info_;
+ struct RequestInfoDeleter
+ {
+ void operator()(QWebEngineUrlRequestInfo *ptr) const
+ { delete ptr; }
+ };
+
+ std::unique_ptr<QWebEngineUrlRequestInfo, RequestInfoDeleter> request_info_;
mojo::Receiver<network::mojom::URLLoader> proxied_loader_receiver_;
mojo::Remote<network::mojom::URLLoaderClient> target_client_;
@@ -192,6 +198,7 @@ InterceptedRequest::InterceptedRequest(ProfileAdapter *profile_adapter,
, request_id_(request_id)
, options_(options)
, request_(request)
+ , request_body_(ResourceRequestBody(request_.request_body.get()))
, traffic_annotation_(traffic_annotation)
, proxied_loader_receiver_(this, std::move(loader_receiver))
, target_client_(std::move(client))
@@ -256,18 +263,25 @@ void InterceptedRequest::Restart()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ bool granted_special_access = false;
+ auto navigationType = toQt(pageTransitionToNavigationType(ui::PageTransition(request_.transition_type)));
+ switch (navigationType) {
+ case QWebEngineUrlRequestInfo::NavigationTypeLink:
+ case QWebEngineUrlRequestInfo::NavigationTypeTyped:
+ if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame && request_.has_user_gesture)
+ granted_special_access = true; // allow normal explicit navigation
+ break;
+ case QWebEngineUrlRequestInfo::NavigationTypeBackForward:
+ case QWebEngineUrlRequestInfo::NavigationTypeReload:
+ if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame)
+ granted_special_access = true;
+ break;
+ default:
+ break;
+ }
+
// Check if non-local access is allowed
if (!allow_remote_ && remote_access_) {
- bool granted_special_access = false;
- switch (ui::PageTransition(request_.transition_type)) {
- case ui::PAGE_TRANSITION_LINK:
- case ui::PAGE_TRANSITION_TYPED:
- if (blink::mojom::ResourceType(request_.resource_type) == blink::mojom::ResourceType::kMainFrame && request_.has_user_gesture)
- granted_special_access = true; // allow normal explicit navigation
- break;
- default:
- break;
- }
if (!granted_special_access) {
target_client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_NETWORK_ACCESS_DENIED));
delete this;
@@ -277,7 +291,6 @@ void InterceptedRequest::Restart()
// Check if local access is allowed
if (!allow_local_ && local_access_) {
- bool granted_special_access = false;
// Check for specifically granted file access:
if (auto *frame_tree = content::FrameTreeNode::GloballyFindByID(frame_tree_node_id_)) {
const int renderer_id = frame_tree->current_frame_host()->GetProcess()->GetID();
@@ -304,7 +317,6 @@ void InterceptedRequest::Restart()
}
auto resourceType = toQt(blink::mojom::ResourceType(request_.resource_type));
- auto navigationType = toQt(pageTransitionToNavigationType(ui::PageTransition(request_.transition_type)));
const QUrl originalUrl = toQt(request_.url);
const QUrl initiator = request_.request_initiator.has_value() ? toQt(request_.request_initiator->GetURL()) : QUrl();
@@ -323,7 +335,7 @@ void InterceptedRequest::Restart()
auto info = new QWebEngineUrlRequestInfoPrivate(
resourceType, navigationType, originalUrl, firstPartyUrl, initiator,
- QByteArray::fromStdString(request_.method), headers);
+ QByteArray::fromStdString(request_.method), &request_body_, headers);
Q_ASSERT(!request_info_);
request_info_.reset(new QWebEngineUrlRequestInfo(info));
@@ -349,22 +361,21 @@ void InterceptedRequest::ContinueAfterIntercept()
if (request_info_) {
// cleanup in scope because of delete this and it's not needed else where after
- decltype(request_info_) scoped_request_info(request_info_.take());
+ const auto scoped_request_info = std::move(request_info_);
QWebEngineUrlRequestInfoPrivate &info = *scoped_request_info->d_ptr;
+ for (auto header = info.extraHeaders.constBegin(); header != info.extraHeaders.constEnd(); ++header) {
+ std::string h = header.key().toStdString();
+ if (base::EqualsCaseInsensitiveASCII(h, "referer"))
+ request_.referrer = GURL(header.value().toStdString());
+ else
+ request_.headers.SetHeader(h, header.value().toStdString());
+ }
+
if (info.changed) {
if (info.shouldBlockRequest)
return SendErrorAndCompleteImmediately(net::ERR_BLOCKED_BY_CLIENT);
- for (auto header = info.extraHeaders.constBegin(); header != info.extraHeaders.constEnd(); ++header) {
- std::string h = header.key().toStdString();
- if (base::EqualsCaseInsensitiveASCII(h, "referer")) {
- request_.referrer = GURL(header.value().toStdString());
- } else {
- request_.headers.SetHeader(h, header.value().toStdString());
- }
- }
-
if (info.shouldRedirectRequest) {
net::RedirectInfo::FirstPartyURLPolicy first_party_url_policy =
request_.update_first_party_url_on_redirect ? net::RedirectInfo::FirstPartyURLPolicy::UPDATE_URL_ON_REDIRECT
diff --git a/src/core/net/qrc_url_scheme_handler.cpp b/src/core/net/qrc_url_scheme_handler.cpp
index ab66acac0..a8b4e4388 100644
--- a/src/core/net/qrc_url_scheme_handler.cpp
+++ b/src/core/net/qrc_url_scheme_handler.cpp
@@ -10,6 +10,8 @@
#include <QMimeDatabase>
#include <QMimeType>
+#include <memory>
+
namespace QtWebEngineCore {
void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job)
@@ -22,7 +24,7 @@ void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job)
QUrl requestUrl = job->requestUrl();
QString requestPath = requestUrl.path();
- QScopedPointer<QFile> file(new QFile(':' + requestPath, job));
+ auto file = std::make_unique<QFile>(':' + requestPath, job);
if (!file->exists() || file->size() == 0) {
qWarning("QResource '%s' not found or is empty", qUtf8Printable(requestPath));
job->fail(QWebEngineUrlRequestJob::UrlNotFound);
@@ -32,9 +34,9 @@ void QrcUrlSchemeHandler::requestStarted(QWebEngineUrlRequestJob *job)
QMimeDatabase mimeDatabase;
QMimeType mimeType = mimeDatabase.mimeTypeForFile(fileInfo);
if (mimeType.name() == QStringLiteral("application/x-extension-html"))
- job->reply("text/html", file.take());
+ job->reply("text/html", file.release());
else
- job->reply(mimeType.name().toUtf8(), file.take());
+ job->reply(mimeType.name().toUtf8(), file.release());
}
} // namespace QtWebEngineCore
diff --git a/src/core/net/resource_request_body_qt.cpp b/src/core/net/resource_request_body_qt.cpp
new file mode 100644
index 000000000..d0d54784d
--- /dev/null
+++ b/src/core/net/resource_request_body_qt.cpp
@@ -0,0 +1,181 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "resource_request_body_qt.h"
+#include "type_conversion.h"
+
+#include "services/network/public/cpp/resource_request_body.h"
+#include "services/network/public/mojom/data_pipe_getter.mojom.h"
+#include "services/network/public/mojom/url_request.mojom-shared.h"
+#include "mojo/public/cpp/bindings/remote.h"
+
+namespace QtWebEngineCore {
+
+ResourceRequestBody::ResourceRequestBody(network::ResourceRequestBody *requestBody, QObject *parent)
+ : QIODevice(parent)
+ , m_requestBody(requestBody)
+ , m_dataElementsIdx(0)
+ , m_dataElementBytesIdx(0)
+ , m_dataElementFileIdx(0)
+{};
+
+ResourceRequestBody::~ResourceRequestBody(){};
+
+qint64 ResourceRequestBody::readData(char *data, qint64 maxSize)
+{
+ if (!m_requestBody)
+ return -1;
+
+ const std::size_t dataElementsSize = m_requestBody->elements()->size();
+ if (m_dataElementsIdx == dataElementsSize)
+ return -1;
+
+ qint64 bytesRead = 0;
+ const std::vector<network::DataElement> *elements = m_requestBody->elements();
+ while (bytesRead < maxSize && m_dataElementsIdx < dataElementsSize) {
+ const network::DataElement &currentDataElement = elements->at(m_dataElementsIdx);
+
+ switch (currentDataElement.type()) {
+ case network::mojom::DataElementDataView::Tag::kBytes: {
+ readDataElementBytes(currentDataElement.As<network::DataElementBytes>().bytes(),
+ bytesRead, maxSize, &data);
+ break;
+ }
+ case network::mojom::DataElementDataView::Tag::kFile: {
+ const network::DataElementFile file = currentDataElement.As<network::DataElementFile>();
+ const qint64 offset = file.offset();
+ const qint64 length = file.length();
+ readDataElementFile(file.path(), offset, length, bytesRead, maxSize, &data);
+ break;
+ }
+ case network::mojom::DataElementDataView::Tag::kDataPipe: {
+ mojo::Remote<network::mojom::DataPipeGetter> pipeGetter;
+ pipeGetter.Bind(
+ currentDataElement.As<network::DataElementDataPipe>().CloneDataPipeGetter());
+ const mojo::ScopedHandleBase<mojo::DataPipeConsumerHandle> consumerHandle =
+ getConsumerHandleFromPipeGetter(pipeGetter);
+ readDataElementPipe(consumerHandle, bytesRead, maxSize, &data);
+ break;
+ }
+ case network::mojom::DataElementDataView::Tag::kChunkedDataPipe: {
+ setErrorString(QStringLiteral("Chunked data pipe is used in request body upload, which "
+ "is currently not supported"));
+ // Nothing should come before or after DataElementChunkedDataPipe
+ return -1;
+ }
+ }
+
+ if (bytesRead == maxSize || m_dataElementsIdx == dataElementsSize)
+ break;
+ }
+
+ return bytesRead;
+}
+
+// We don't want to write, ever
+qint64 ResourceRequestBody::writeData(const char *data, qint64 maxSize)
+{
+ return -1;
+}
+
+bool ResourceRequestBody::isSequential() const
+{
+ return true;
+}
+
+void ResourceRequestBody::readDataElementBytes(const std::vector<uint8_t> &dataElement,
+ qint64 &bytesRead, const qint64 &maxSize,
+ char **data)
+{
+ const std::size_t dataElementSize = dataElement.size();
+ const std::size_t bytesToRead = std::min(dataElementSize, static_cast<std::size_t>(maxSize));
+
+ std::memcpy(*data, dataElement.data(), bytesToRead);
+ *data += bytesToRead;
+ m_dataElementBytesIdx += bytesToRead;
+ bytesRead += bytesToRead;
+
+ if (m_dataElementBytesIdx == dataElementSize) {
+ m_dataElementsIdx++;
+ m_dataElementBytesIdx = 0;
+ }
+}
+
+void ResourceRequestBody::readDataElementFile(const base::FilePath &filePath, const qint64 &offset,
+ const qint64 &length, qint64 &bytesRead,
+ const qint64 &maxSize, char **data)
+{
+ QFile file(toQt(filePath.value()));
+ const qint64 realOffset = offset + m_dataElementFileIdx;
+ const std::size_t fileSize = std::min(file.size(), length) - realOffset;
+ const std::size_t bytesToRead = std::min(fileSize, static_cast<std::size_t>(maxSize));
+
+ file.open(QFile::ReadOnly);
+ file.seek(realOffset);
+
+ std::memcpy(*data, file.read(bytesToRead).data(), bytesToRead);
+ *data += bytesToRead;
+ m_dataElementFileIdx += bytesToRead;
+ bytesRead += bytesToRead;
+
+ file.close();
+
+ if (m_dataElementFileIdx == fileSize) {
+ m_dataElementsIdx++;
+ m_dataElementFileIdx = 0;
+ }
+}
+
+mojo::ScopedHandleBase<mojo::DataPipeConsumerHandle>
+ResourceRequestBody::getConsumerHandleFromPipeGetter(
+ mojo::Remote<network::mojom::DataPipeGetter> &pipeGetter)
+{
+ mojo::ScopedHandleBase<mojo::DataPipeProducerHandle> producerHandle;
+ mojo::ScopedHandleBase<mojo::DataPipeConsumerHandle> consumerHandle;
+ mojo::CreateDataPipe(nullptr, producerHandle, consumerHandle);
+ base::WeakPtrFactory<ResourceRequestBody> weakPtrFactory{ this };
+ pipeGetter->Read(std::move(producerHandle),
+ base::BindOnce(&ResourceRequestBody::pipeGetterOnReadComplete,
+ weakPtrFactory.GetWeakPtr()));
+
+ return consumerHandle;
+}
+
+void ResourceRequestBody::readDataElementPipe(
+ const mojo::ScopedHandleBase<mojo::DataPipeConsumerHandle> &consumerHandle,
+ qint64 &bytesRead, const qint64 &maxSize, char **data)
+{
+ MojoResult result;
+ do {
+ uint32_t bytesToRead = 1;
+ result = consumerHandle->ReadData(*data, &bytesToRead, MOJO_READ_DATA_FLAG_NONE);
+
+ if (result == MOJO_RESULT_OK) {
+ *data += bytesToRead;
+ bytesRead += bytesToRead;
+ } else if (result != MOJO_RESULT_SHOULD_WAIT && result != MOJO_RESULT_FAILED_PRECONDITION) {
+ setErrorString(QString::fromLatin1("Error while reading from data pipe, skipping"
+ "remaining content of data pipe. Mojo error code: ")
+ + QString::number(result));
+ }
+ } while ((result == MOJO_RESULT_SHOULD_WAIT || result == MOJO_RESULT_OK)
+ && bytesRead < maxSize);
+
+ m_dataElementsIdx++;
+}
+
+void ResourceRequestBody::pipeGetterOnReadComplete(int32_t status, uint64_t size) { }
+
+void ResourceRequestBody::appendFilesForTest(const QString &path)
+{
+ if (!m_requestBody)
+ return;
+
+ base::FilePath filePath = toFilePath(path);
+ m_requestBody->elements_mutable()->push_back(static_cast<network::DataElement>(
+ network::DataElementFile(filePath, 0, 23, base::Time())));
+ m_requestBody->elements_mutable()->push_back(static_cast<network::DataElement>(
+ network::DataElementFile(filePath, 10, 23, base::Time())));
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/net/resource_request_body_qt.h b/src/core/net/resource_request_body_qt.h
new file mode 100644
index 000000000..717885d7d
--- /dev/null
+++ b/src/core/net/resource_request_body_qt.h
@@ -0,0 +1,70 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef RESOURCEREQUESTBODY_QT_H
+#define RESOURCEREQUESTBODY_QT_H
+
+#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
+#include <QtCore/QIODevice>
+#include <QtCore/QFile>
+#include <QtCore/QUrl>
+
+namespace network {
+class ResourceRequestBody;
+namespace mojom {
+class DataPipeGetter;
+class ChunkedDataPipeGetter;
+}
+}
+
+namespace base {
+class FilePath;
+}
+
+namespace mojo {
+template<typename T>
+class Remote;
+template<typename T>
+class ScopedHandleBase;
+class DataPipeConsumerHandle;
+}
+
+namespace QtWebEngineCore {
+
+class Q_WEBENGINECORE_EXPORT ResourceRequestBody : public QIODevice
+{
+ Q_OBJECT
+public:
+ explicit ResourceRequestBody(network::ResourceRequestBody *requestBody,
+ QObject *parent = nullptr);
+ ~ResourceRequestBody();
+
+ qint64 readData(char *data, qint64 maxSize) override;
+ qint64 writeData(const char *data, qint64 maxSize) override;
+ bool isSequential() const override;
+
+ void appendFilesForTest(const QString &path);
+
+private:
+ network::ResourceRequestBody *const m_requestBody;
+
+ std::size_t m_dataElementsIdx;
+ std::size_t m_dataElementBytesIdx;
+ std::size_t m_dataElementFileIdx;
+
+ void readDataElementBytes(const std::vector<uint8_t> &dataElement, qint64 &bytesRead,
+ const qint64 &maxSize, char **data);
+ void readDataElementFile(const base::FilePath &filePath, const qint64 &offset,
+ const qint64 &length, qint64 &bytesRead, const qint64 &maxSize,
+ char **data);
+ mojo::ScopedHandleBase<mojo::DataPipeConsumerHandle>
+ getConsumerHandleFromPipeGetter(mojo::Remote<network::mojom::DataPipeGetter> &pipeGetter);
+ void
+ readDataElementPipe(const mojo::ScopedHandleBase<mojo::DataPipeConsumerHandle> &consumerHandle,
+ qint64 &bytesRead, const qint64 &maxSize, char **data);
+ void pipeGetterOnReadComplete(int32_t status, uint64_t size);
+};
+
+} // namespace QtWebEngineCore
+
+#endif // RESOURCEREQUESTBODY_QT_H
diff --git a/src/core/net/ssl_host_state_delegate_qt.cpp b/src/core/net/ssl_host_state_delegate_qt.cpp
index d0308389d..41967f14e 100644
--- a/src/core/net/ssl_host_state_delegate_qt.cpp
+++ b/src/core/net/ssl_host_state_delegate_qt.cpp
@@ -3,7 +3,7 @@
#include "ssl_host_state_delegate_qt.h"
-#include "base/callback.h"
+#include "base/functional/callback.h"
namespace QtWebEngineCore {
@@ -111,5 +111,26 @@ bool SSLHostStateDelegateQt::HasAllowException(const std::string &host, content:
policy_iterator->second.HasAllowException();
}
+bool SSLHostStateDelegateQt::HasAllowExceptionForAnyHost(content::StoragePartition *storage_partition)
+{
+ for (auto const &it : m_certPolicyforHost) {
+ if (it.second.HasAllowException()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void SSLHostStateDelegateQt::SetHttpsEnforcementForHost(const std::string &host, bool enforce,
+ content::StoragePartition *storage_partition)
+{
+ // Intentional no-op see aw_ssl_host_state_delegate
+}
+
+bool SSLHostStateDelegateQt::IsHttpsEnforcedForHost(const std::string &host, content::StoragePartition *storage_partition)
+{
+ // Intentional no-op
+ return false;
+}
} // namespace QtWebEngineCore
diff --git a/src/core/net/ssl_host_state_delegate_qt.h b/src/core/net/ssl_host_state_delegate_qt.h
index 380e59f2c..0b3d7974c 100644
--- a/src/core/net/ssl_host_state_delegate_qt.h
+++ b/src/core/net/ssl_host_state_delegate_qt.h
@@ -39,8 +39,11 @@ public:
bool DidHostRunInsecureContent(const std::string &host, int child_id, InsecureContentType content_type) override;
void AllowHttpForHost(const std::string &host, content::StoragePartition *web_contents) override;
bool IsHttpAllowedForHost(const std::string &host, content::StoragePartition *web_contents) override;
+ void SetHttpsEnforcementForHost(const std::string &host, bool enforce, content::StoragePartition *storage_partition) override;
+ bool IsHttpsEnforcedForHost(const std::string &host, content::StoragePartition *web_contents) override;
void RevokeUserAllowExceptions(const std::string &host) override;
bool HasAllowException(const std::string &host, content::StoragePartition *web_contents) override;
+ bool HasAllowExceptionForAnyHost(content::StoragePartition *storage_partition) override;
private:
std::map<std::string, CertPolicy> m_certPolicyforHost;
diff --git a/src/core/net/system_network_context_manager.cpp b/src/core/net/system_network_context_manager.cpp
index 83e122aab..439d1066c 100644
--- a/src/core/net/system_network_context_manager.cpp
+++ b/src/core/net/system_network_context_manager.cpp
@@ -8,8 +8,8 @@
#include "net/system_network_context_manager.h"
-#include "base/bind.h"
#include "base/command_line.h"
+#include "base/functional/bind.h"
#include "base/strings/string_split.h"
#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
#include "chrome/common/chrome_switches.h"
@@ -29,17 +29,21 @@
#include "services/network/public/mojom/cert_verifier_service.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+#include "api/qwebengineglobalsettings.h"
+#include "api/qwebengineglobalsettings_p.h"
#if BUILDFLAG(IS_WIN)
#include "chrome/browser/net/chrome_mojo_proxy_resolver_win.h"
-#include "components/os_crypt/os_crypt.h"
-#include "content/public/common/network_service_util.h"
+#include "components/os_crypt/sync/os_crypt.h"
+#include "content/public/browser/network_service_util.h"
#endif
-namespace {
+ASSERT_ENUMS_MATCH(net::SecureDnsMode::kSecure, QWebEngineGlobalSettings::SecureDnsMode::SecureOnly)
+ASSERT_ENUMS_MATCH(net::SecureDnsMode::kAutomatic,
+ QWebEngineGlobalSettings::SecureDnsMode::SecureWithFallback)
+ASSERT_ENUMS_MATCH(net::SecureDnsMode::kOff, QWebEngineGlobalSettings::SecureDnsMode::SystemOnly)
-// The global instance of the SystemNetworkContextmanager.
-SystemNetworkContextManager *g_system_network_context_manager = nullptr;
+namespace {
network::mojom::HttpAuthStaticParamsPtr CreateHttpAuthStaticParams()
{
@@ -65,6 +69,11 @@ network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams()
} // namespace
+namespace QtWebEngineCore {
+
+// The global instance of the SystemNetworkContextmanager.
+SystemNetworkContextManager *g_system_network_context_manager = nullptr;
+
// SharedURLLoaderFactory backed by a SystemNetworkContextManager and its
// network context. Transparently handles crashes.
class SystemNetworkContextManager::URLLoaderFactoryForSystem : public network::SharedURLLoaderFactory
@@ -255,12 +264,13 @@ void SystemNetworkContextManager::OnNetworkServiceCreated(network::mojom::Networ
network_service->SetExplicitlyAllowedPorts(explicitly_allowed_network_ports);
}
- // Configure the stub resolver. This must be done after the system
- // NetworkContext is created, but before anything has the chance to use it.
- // bool stub_resolver_enabled;
- // absl::optional<std::vector<network::mojom::DnsOverHttpsServerPtr>> dns_over_https_servers;
- // GetStubResolverConfig(local_state_, &stub_resolver_enabled, &dns_over_https_servers);
- // content::GetNetworkService()->ConfigureStubHostResolver(stub_resolver_enabled, std::move(dns_over_https_servers));
+
+ // The network service is a singleton that can be reinstantiated for different reasons,
+ // e.g., when the network service crashes. Therefore, we configure the stub host
+ // resolver of the network service here, each time it is instantiated, with our global
+ // DNS-Over-HTTPS settings. This ensures that the global settings don't get lost
+ // on reinstantiation and are in effect upon initial instantiation.
+ QWebEngineGlobalSettingsPrivate::instance()->configureStubHostResolver();
}
void SystemNetworkContextManager::AddSSLConfigToNetworkContextParams(network::mojom::NetworkContextParams *network_context_params)
@@ -320,3 +330,30 @@ network::mojom::NetworkContextParamsPtr SystemNetworkContextManager::CreateNetwo
content::GetCertVerifierParams(std::move(cert_verifier_creation_params));
return network_context_params;
}
+
+bool isValidTemplates(std::string templates)
+{
+ absl::optional<net::DnsOverHttpsConfig> dnsOverHttpsConfig =
+ net::DnsOverHttpsConfig::FromString(templates);
+ return dnsOverHttpsConfig.has_value();
+}
+
+
+void configureStubHostResolver(QWebEngineGlobalSettings::SecureDnsMode dnsMode,
+ std::string dnsOverHttpsTemplates, bool insecureDnsClientEnabled,
+ bool additionalInsecureDnsTypesEnabled)
+{
+ if (content::IsNetworkServiceCreated()) {
+ network::mojom::NetworkService *networkService = content::GetNetworkService();
+ if (networkService) {
+ absl::optional<net::DnsOverHttpsConfig> dohConfig = dnsOverHttpsTemplates.empty()
+ ? net::DnsOverHttpsConfig()
+ : net::DnsOverHttpsConfig::FromString(dnsOverHttpsTemplates);
+ networkService->ConfigureStubHostResolver(insecureDnsClientEnabled,
+ net::SecureDnsMode(dnsMode), *dohConfig,
+ additionalInsecureDnsTypesEnabled);
+ }
+ }
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/net/system_network_context_manager.h b/src/core/net/system_network_context_manager.h
index fa761cb44..d56bdab78 100644
--- a/src/core/net/system_network_context_manager.h
+++ b/src/core/net/system_network_context_manager.h
@@ -28,6 +28,8 @@ class URLLoaderFactory;
class SharedURLLoaderFactory;
} // namespace network
+namespace QtWebEngineCore {
+
// Responsible for creating and managing access to the system NetworkContext.
// Lives on the UI thread. The NetworkContext this owns is intended for requests
// not associated with a profile. It stores no data on disk, and has no HTTP
@@ -114,4 +116,6 @@ private:
ProxyConfigMonitor proxy_config_monitor_;
};
+} // namespace QtWebEngineCore
+
#endif // SYSTEM_NETWORK_CONTEXT_MANAGER_H_
diff --git a/src/core/net/url_request_custom_job_delegate.cpp b/src/core/net/url_request_custom_job_delegate.cpp
index 07a1de1ec..c877de669 100644
--- a/src/core/net/url_request_custom_job_delegate.cpp
+++ b/src/core/net/url_request_custom_job_delegate.cpp
@@ -14,16 +14,16 @@
namespace QtWebEngineCore {
-URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy,
- const QUrl &url,
- const QByteArray &method,
- const QUrl &initiatorOrigin,
- const QMap<QByteArray, QByteArray> &headers)
- : m_proxy(proxy),
- m_request(url),
- m_method(method),
- m_initiatorOrigin(initiatorOrigin),
- m_requestHeaders(headers)
+URLRequestCustomJobDelegate::URLRequestCustomJobDelegate(
+ URLRequestCustomJobProxy *proxy, const QUrl &url, const QByteArray &method,
+ const QUrl &initiatorOrigin, const QMap<QByteArray, QByteArray> &headers,
+ network::ResourceRequestBody *requestBody)
+ : m_proxy(proxy)
+ , m_request(url)
+ , m_method(method)
+ , m_initiatorOrigin(initiatorOrigin)
+ , m_requestHeaders(headers)
+ , m_resourceRequestBody(ResourceRequestBody(requestBody))
{
}
@@ -51,8 +51,13 @@ QMap<QByteArray, QByteArray> URLRequestCustomJobDelegate::requestHeaders() const
return m_requestHeaders;
}
+QIODevice *URLRequestCustomJobDelegate::requestBody()
+{
+ return &m_resourceRequestBody;
+}
+
void URLRequestCustomJobDelegate::setAdditionalResponseHeaders(
- const QMap<QByteArray, QByteArray> &additionalResponseHeaders)
+ const QMultiMap<QByteArray, QByteArray> &additionalResponseHeaders)
{
m_additionalResponseHeaders = additionalResponseHeaders;
}
diff --git a/src/core/net/url_request_custom_job_delegate.h b/src/core/net/url_request_custom_job_delegate.h
index 6b6ee68cf..63db46464 100644
--- a/src/core/net/url_request_custom_job_delegate.h
+++ b/src/core/net/url_request_custom_job_delegate.h
@@ -17,6 +17,7 @@
#include "base/memory/ref_counted.h"
#include "qtwebenginecoreglobal_p.h"
+#include "resource_request_body_qt.h"
#include <QMap>
#include <QObject>
@@ -24,11 +25,15 @@
QT_FORWARD_DECLARE_CLASS(QIODevice)
+namespace network {
+class ResourceRequestBody;
+}
+
namespace QtWebEngineCore {
class URLRequestCustomJobProxy;
-class Q_WEBENGINECORE_PRIVATE_EXPORT URLRequestCustomJobDelegate : public QObject
+class Q_WEBENGINECORE_EXPORT URLRequestCustomJobDelegate : public QObject
{
Q_OBJECT
public:
@@ -47,9 +52,10 @@ public:
QByteArray method() const;
QUrl initiator() const;
QMap<QByteArray, QByteArray> requestHeaders() const;
+ QIODevice *requestBody();
void
- setAdditionalResponseHeaders(const QMap<QByteArray, QByteArray> &additionalResponseHeaders);
+ setAdditionalResponseHeaders(const QMultiMap<QByteArray, QByteArray> &additionalResponseHeaders);
void reply(const QByteArray &contentType, QIODevice *device);
void redirect(const QUrl &url);
void abort();
@@ -59,11 +65,10 @@ private Q_SLOTS:
void slotReadyRead();
private:
- URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy,
- const QUrl &url,
- const QByteArray &method,
- const QUrl &initiatorOrigin,
- const QMap<QByteArray, QByteArray> &requestHeaders);
+ URLRequestCustomJobDelegate(URLRequestCustomJobProxy *proxy, const QUrl &url,
+ const QByteArray &method, const QUrl &initiatorOrigin,
+ const QMap<QByteArray, QByteArray> &requestHeaders,
+ network::ResourceRequestBody *requestBody);
friend class URLRequestCustomJobProxy;
scoped_refptr<URLRequestCustomJobProxy> m_proxy;
@@ -71,7 +76,8 @@ private:
QByteArray m_method;
QUrl m_initiatorOrigin;
const QMap<QByteArray, QByteArray> m_requestHeaders;
- QMap<QByteArray, QByteArray> m_additionalResponseHeaders;
+ QMultiMap<QByteArray, QByteArray> m_additionalResponseHeaders;
+ ResourceRequestBody m_resourceRequestBody;
};
} // namespace
diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp
index d7adcc7e8..0f41a3670 100644
--- a/src/core/net/url_request_custom_job_proxy.cpp
+++ b/src/core/net/url_request_custom_job_proxy.cpp
@@ -6,6 +6,7 @@
#include "content/public/browser/browser_thread.h"
#include "net/base/net_errors.h"
+#include "services/network/public/cpp/resource_request_body.h"
#include "api/qwebengineurlrequestjob.h"
#include "profile_adapter.h"
@@ -41,7 +42,7 @@ void URLRequestCustomJobProxy::release()
}
void URLRequestCustomJobProxy::reply(std::string contentType, QIODevice *device,
- QMap<QByteArray, QByteArray> additionalResponseHeaders)
+ QMultiMap<QByteArray, QByteArray> additionalResponseHeaders)
{
if (!m_client)
return;
@@ -51,15 +52,15 @@ void URLRequestCustomJobProxy::reply(std::string contentType, QIODevice *device,
if (sidx > 0) {
const int cidx = qcontentType.indexOf("charset=", sidx);
if (cidx > 0) {
- m_client->m_charset = qcontentType.mid(cidx + 8).toStdString();
+ m_client->m_charset = qcontentType.mid(cidx + 8).trimmed().toStdString();
qcontentType = qcontentType.first(sidx);
} else {
qWarning() << "QWebEngineUrlRequestJob::reply(): Unrecognized content-type format with ';'" << qcontentType;
}
}
- m_client->m_mimeType = qcontentType.toStdString();
+ m_client->m_mimeType = qcontentType.trimmed().toStdString();
m_client->m_device = device;
- m_client->m_additionalResponseHeaders = additionalResponseHeaders;
+ m_client->m_additionalResponseHeaders = std::move(additionalResponseHeaders);
if (m_client->m_device && !m_client->m_device->isReadable())
m_client->m_device->open(QIODevice::ReadOnly);
@@ -126,7 +127,8 @@ void URLRequestCustomJobProxy::readyRead()
void URLRequestCustomJobProxy::initialize(GURL url, std::string method,
absl::optional<url::Origin> initiator,
- std::map<std::string, std::string> headers)
+ std::map<std::string, std::string> headers,
+ scoped_refptr<network::ResourceRequestBody> requestBody)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
Q_ASSERT(!m_delegate);
@@ -144,10 +146,9 @@ void URLRequestCustomJobProxy::initialize(GURL url, std::string method,
qHeaders.insert(toQByteArray(it->first), toQByteArray(it->second));
if (schemeHandler) {
- m_delegate = new URLRequestCustomJobDelegate(this, toQt(url),
- QByteArray::fromStdString(method),
- initiatorOrigin,
- qHeaders);
+ m_delegate =
+ new URLRequestCustomJobDelegate(this, toQt(url), QByteArray::fromStdString(method),
+ initiatorOrigin, qHeaders, requestBody.get());
QWebEngineUrlRequestJob *requestJob = new QWebEngineUrlRequestJob(m_delegate);
schemeHandler->requestStarted(requestJob);
}
diff --git a/src/core/net/url_request_custom_job_proxy.h b/src/core/net/url_request_custom_job_proxy.h
index 1f8c77da2..65c919ed0 100644
--- a/src/core/net/url_request_custom_job_proxy.h
+++ b/src/core/net/url_request_custom_job_proxy.h
@@ -4,7 +4,6 @@
#ifndef URL_REQUEST_CUSTOM_JOB_PROXY_H_
#define URL_REQUEST_CUSTOM_JOB_PROXY_H_
-#include "base/memory/weak_ptr.h"
#include "base/task/sequenced_task_runner.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "url/gurl.h"
@@ -15,6 +14,10 @@
QT_FORWARD_DECLARE_CLASS(QIODevice)
+namespace network {
+class ResourceRequestBody;
+}
+
namespace QtWebEngineCore {
class URLRequestCustomJob;
@@ -31,7 +34,7 @@ public:
public:
std::string m_mimeType;
std::string m_charset;
- QMap<QByteArray, QByteArray> m_additionalResponseHeaders;
+ QMultiMap<QByteArray, QByteArray> m_additionalResponseHeaders;
GURL m_redirect;
QIODevice *m_device;
int64_t m_firstBytePosition;
@@ -53,12 +56,14 @@ public:
// Called from URLRequestCustomJobDelegate via post:
//void setReplyCharset(const std::string &);
void reply(std::string mimeType, QIODevice *device,
- QMap<QByteArray, QByteArray> additionalResponseHeaders);
+ QMultiMap<QByteArray, QByteArray> additionalResponseHeaders);
void redirect(GURL url);
void abort();
void fail(int error);
void release();
- void initialize(GURL url, std::string method, absl::optional<url::Origin> initiatorOrigin, std::map<std::string, std::string> headers);
+ void initialize(GURL url, std::string method, absl::optional<url::Origin> initiatorOrigin,
+ std::map<std::string, std::string> headers,
+ scoped_refptr<network::ResourceRequestBody> requestBody);
void readyRead();
// IO thread owned:
diff --git a/src/core/net/version_ui_qt.cpp b/src/core/net/version_ui_qt.cpp
new file mode 100644
index 000000000..61a89596a
--- /dev/null
+++ b/src/core/net/version_ui_qt.cpp
@@ -0,0 +1,56 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "version_ui_qt.h"
+#include "api/qtwebenginecoreglobal.h"
+#include "build/build_config.h"
+#include "base/command_line.h"
+#include "chrome/common/url_constants.h"
+#include "chrome/browser/profiles/profile.h"
+#include "qtwebengine/grit/qt_webengine_resources.h"
+#include "services/network/public/cpp/content_security_policy/content_security_policy.h"
+
+namespace {
+const char kQtWebEngineVersion[] = "qtwebengine_version";
+const char kQtWebEngineChromiumVersion[] = "qtwebengine_chromium_version";
+const char kQtWebEngineChromiumSecurityPatchVersion[] =
+ "qtwebengine_chromium_security_patch_version";
+const char kCommandLine[] = "command_line";
+const char kQtVersionCSS[] = "qt_version.css";
+const char kQtLogo[] = "images/qt.png";
+const char kQtWebEngineLogo[] = "images/qtwebengine.png";
+}
+
+VersionUIQt::VersionUIQt(content::WebUI *web_ui) : content::WebUIController(web_ui)
+{
+
+ Profile *profile = Profile::FromWebUI(web_ui);
+ content::WebUIDataSource *html_source =
+ content::WebUIDataSource::CreateAndAdd(profile, chrome::kChromeUIVersionQtHost);
+ html_source->OverrideContentSecurityPolicy(
+ network::mojom::CSPDirectiveName::ScriptSrc,
+ "script-src chrome://resources 'self' 'unsafe-inline';");
+ html_source->SetDefaultResource(IDR_VERSION_UI_QT_HTML);
+ html_source->AddResourcePath(kQtVersionCSS, IDR_VERSION_UI_QT_CSS);
+ html_source->AddResourcePath(kQtLogo, IDR_QT_LOGO);
+ html_source->AddResourcePath(kQtWebEngineLogo, IDR_QTWEBENGINE_LOGO);
+
+ html_source->AddString(kQtWebEngineVersion, qWebEngineVersion());
+ html_source->AddString(kQtWebEngineChromiumVersion, qWebEngineChromiumVersion());
+ html_source->AddString(kQtWebEngineChromiumSecurityPatchVersion,
+ qWebEngineChromiumSecurityPatchVersion());
+#if BUILDFLAG(IS_WIN)
+ html_source->AddString(
+ kCommandLine,
+ base::AsString16(base::CommandLine::ForCurrentProcess()->GetCommandLineString()));
+#else
+ std::string command_line;
+ typedef std::vector<std::string> ArgvList;
+ const ArgvList &argv = base::CommandLine::ForCurrentProcess()->argv();
+ for (auto iter = argv.begin(); iter != argv.end(); iter++)
+ command_line += " " + *iter;
+ html_source->AddString(kCommandLine, command_line);
+#endif
+}
+
+VersionUIQt::~VersionUIQt() { }
diff --git a/src/core/net/version_ui_qt.h b/src/core/net/version_ui_qt.h
new file mode 100644
index 000000000..1fe8ef9e0
--- /dev/null
+++ b/src/core/net/version_ui_qt.h
@@ -0,0 +1,32 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+//
+// 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.
+//
+
+#ifndef VERSION_UI_QT_H_
+#define VERSION_UI_QT_H_
+
+#include "build/build_config.h"
+#include "content/public/browser/web_ui_controller.h"
+#include "content/public/browser/web_ui_data_source.h"
+
+class VersionUIQt : public content::WebUIController
+{
+public:
+ explicit VersionUIQt(content::WebUI *web_ui);
+ ~VersionUIQt() override;
+
+ VersionUIQt(const VersionUIQt &) = delete;
+ VersionUIQt &operator=(const VersionUIQt &) = delete;
+};
+
+#endif // VERSION_UI_QT_H
diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp
index 0551d9be7..ed35a3e36 100644
--- a/src/core/net/webui_controller_factory_qt.cpp
+++ b/src/core/net/webui_controller_factory_qt.cpp
@@ -10,8 +10,7 @@
#include "build_config_qt.h"
#include "devtools_frontend_qt.h"
-
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "build/build_config.h"
#include "chrome/browser/accessibility/accessibility_ui.h"
#include "chrome/browser/profiles/profile.h"
@@ -26,6 +25,7 @@
#include "media/media_buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "url/gurl.h"
+#include "version_ui_qt.h"
#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
#include "chrome/browser/ui/webui/sandbox/sandbox_internals_ui.h"
@@ -86,11 +86,11 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co
// This will get called a lot to check all URLs, so do a quick check of other
// schemes to filter out most URLs.
if (!content::HasWebUIScheme(url))
- return NULL;
+ return nullptr;
// We must compare hosts only since some of the Web UIs append extra stuff
// after the host name.
- if (url.host() == chrome::kChromeUINetInternalsHost)
+ if (url.host_piece() == chrome::kChromeUINetInternalsHost)
return &NewWebUI<NetInternalsUI>;
if (url.SchemeIs(content::kChromeDevToolsScheme)) {
@@ -98,7 +98,7 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co
return nullptr;
return &NewWebUI<DevToolsUI>;
}
- if (url.host() == chrome::kChromeUIAccessibilityHost)
+ if (url.host_piece() == chrome::kChromeUIAccessibilityHost)
return &NewWebUI<AccessibilityUI>;
if (url.host_piece() == chrome::kChromeUIUserActionsHost)
@@ -107,6 +107,9 @@ WebUIFactoryFunction GetWebUIFactoryFunction(WebUI *web_ui, Profile *profile, co
if (url.host_piece() == chrome::kChromeUIDeviceLogHost)
return &NewWebUI<chromeos::DeviceLogUI>;
+ if (url.host_piece() == chrome::kChromeUIVersionQtHost)
+ return &NewWebUI<VersionUIQt>;
+
// if (url.host_piece() == chrome::kChromeUIInspectHost)
// return &NewWebUI<InspectUI>;
//
diff --git a/src/core/ozone/gl_context_qt.cpp b/src/core/ozone/gl_context_qt.cpp
index 75f8e8422..0042f2bce 100644
--- a/src/core/ozone/gl_context_qt.cpp
+++ b/src/core/ozone/gl_context_qt.cpp
@@ -8,10 +8,21 @@
#include <QThread>
#include <QtGui/private/qtgui-config_p.h>
#include <qpa/qplatformnativeinterface.h>
-#include "ui/gl/gl_context_egl.h"
+
#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_surface.h"
+
+#if defined(USE_OZONE)
+#include "ui/gl/egl_util.h"
+
+#include <QOpenGLFunctions>
+#include <QOffscreenSurface>
+
+#include <vector>
+#endif
#if BUILDFLAG(IS_WIN)
+#include "ui/gl/gl_context_egl.h"
#include "ui/gl/gl_context_wgl.h"
#endif
@@ -27,7 +38,8 @@ inline void *resourceForContext(const QByteArray &resource)
#if QT_CONFIG(opengl)
QOpenGLContext *shareContext = qt_gl_global_share_context();
if (!shareContext) {
- qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to call QtWebEngineCore::initialize() in your main() function.");
+ qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to "
+ "call QtWebEngineQuick::initialize() in your main() function.");
}
return qApp->platformNativeInterface()->nativeResourceForContext(resource, shareContext);
#else
@@ -163,30 +175,225 @@ bool GLContextHelper::isCreateContextRobustnessSupported()
return contextHelper->m_robustness;
}
+#if QT_CONFIG(opengl) && defined(USE_OZONE)
+class ScopedGLContext
+{
+public:
+ ScopedGLContext()
+ : m_context(new QOpenGLContext())
+ , m_previousContext(gl::GLContext::GetCurrent())
+ , m_previousSurface(gl::GLSurface::GetCurrent())
+ {
+ if (!m_context->create()) {
+ qWarning("Failed to create OpenGL context.");
+ return;
+ }
+
+ QOffscreenSurface *surface = new QOffscreenSurface(m_context->screen(), m_context.get());
+ surface->create();
+ Q_ASSERT(surface->isValid());
+
+ if (!m_context->makeCurrent(surface)) {
+ qWarning("Failed to make OpenGL context current.");
+ return;
+ }
+ }
+
+ ~ScopedGLContext()
+ {
+ if (!m_textures.empty()) {
+ auto glFun = m_context->functions();
+ glFun->glDeleteTextures(m_textures.size(), m_textures.data());
+ }
+
+ if (m_previousContext)
+ m_previousContext->MakeCurrent(m_previousSurface);
+ }
+
+ bool isValid() const { return m_context->isValid() && (m_context->surface() != nullptr); }
+
+ EGLDisplay eglDisplay() const
+ {
+ QNativeInterface::QEGLContext *nativeInterface =
+ m_context->nativeInterface<QNativeInterface::QEGLContext>();
+ return nativeInterface->display();
+ }
+
+ EGLContext eglContext() const
+ {
+ QNativeInterface::QEGLContext *nativeInterface =
+ m_context->nativeInterface<QNativeInterface::QEGLContext>();
+ return nativeInterface->nativeContext();
+ }
+
+ uint createTexture(int width, int height)
+ {
+ auto glFun = m_context->functions();
+
+ uint glTexture;
+ glFun->glGenTextures(1, &glTexture);
+ glFun->glBindTexture(GL_TEXTURE_2D, glTexture);
+ glFun->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
+ NULL);
+ glFun->glBindTexture(GL_TEXTURE_2D, 0);
+
+ m_textures.push_back(glTexture);
+ return glTexture;
+ }
+
+private:
+ QScopedPointer<QOpenGLContext> m_context;
+ gl::GLContext *m_previousContext;
+ gl::GLSurface *m_previousSurface;
+ std::vector<uint> m_textures;
+};
+
+EGLHelper::EGLFunctions::EGLFunctions()
+{
+ const static auto getProcAddress =
+ reinterpret_cast<gl::GLGetProcAddressProc>(GLContextHelper::getEglGetProcAddress());
+
+ eglCreateImage = reinterpret_cast<PFNEGLCREATEIMAGEPROC>(getProcAddress("eglCreateImage"));
+ eglDestroyImage = reinterpret_cast<PFNEGLDESTROYIMAGEPROC>(getProcAddress("eglDestroyImage"));
+ eglGetError = reinterpret_cast<PFNEGLGETERRORPROC>(getProcAddress("eglGetError"));
+ eglExportDMABUFImageMESA = reinterpret_cast<PFNEGLEXPORTDMABUFIMAGEMESAPROC>(
+ getProcAddress("eglExportDMABUFImageMESA"));
+ eglExportDMABUFImageQueryMESA = reinterpret_cast<PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC>(
+ getProcAddress("eglExportDMABUFImageQueryMESA"));
+ eglQueryString = reinterpret_cast<PFNEGLQUERYSTRINGPROC>(getProcAddress("eglQueryString"));
+}
+
+EGLHelper *EGLHelper::instance()
+{
+ static EGLHelper eglHelper;
+ return &eglHelper;
+}
+
+EGLHelper::EGLHelper() : m_functions(new EGLHelper::EGLFunctions())
+{
+ const char *extensions = m_functions->eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ if (!extensions) {
+ qWarning("EGL: Failed to query EGL extensions.");
+ return;
+ }
+
+ if (strstr(extensions, "EGL_KHR_base_image")) {
+ qWarning("EGL: EGL_KHR_base_image extension is not supported.");
+ return;
+ }
+
+ auto eglDisplay = GLContextHelper::getEGLDisplay();
+ if (!eglDisplay) {
+ qWarning("EGL: No EGL display.");
+ return;
+ }
+
+ const char *displayExtensions = m_functions->eglQueryString(eglDisplay, EGL_EXTENSIONS);
+ m_isDmaBufSupported = strstr(displayExtensions, "EGL_EXT_image_dma_buf_import")
+ && strstr(displayExtensions, "EGL_EXT_image_dma_buf_import_modifiers")
+ && strstr(displayExtensions, "EGL_MESA_image_dma_buf_export");
+
+ if (m_isDmaBufSupported) {
+ // FIXME: This disables GBM for nvidia. Remove this when nvidia fixes its GBM support.
+ //
+ // "Buffer allocation and submission to DRM KMS using gbm is not currently supported."
+ // See: https://download.nvidia.com/XFree86/Linux-x86_64/550.40.07/README/kms.html
+ //
+ // Chromium uses GBM to allocate scanout buffers. Scanout requires DRM KMS. If KMS is
+ // enabled, gbm_device and gbm_buffer are created without any issues but rendering to the
+ // buffer will malfunction. It is not known how to detect this problem before rendering
+ // so we just disable GBM for nvidia.
+ const char *displayVendor = m_functions->eglQueryString(eglDisplay, EGL_VENDOR);
+ m_isDmaBufSupported = !strstr(displayVendor, "NVIDIA");
+ }
+}
+
+void EGLHelper::queryDmaBuf(const int width, const int height, int *fd, int *stride, int *offset,
+ uint64_t *modifiers)
+{
+ if (!m_isDmaBufSupported)
+ return;
+
+ ScopedGLContext context;
+ if (!context.isValid())
+ return;
+
+ EGLDisplay eglDisplay = context.eglDisplay();
+ EGLContext eglContext = context.eglContext();
+ if (!eglContext) {
+ qWarning("EGL: No EGLContext.");
+ return;
+ }
+
+ uint64_t textureId = context.createTexture(width, height);
+ EGLImage eglImage = m_functions->eglCreateImage(eglDisplay, eglContext, EGL_GL_TEXTURE_2D,
+ (EGLClientBuffer)textureId, NULL);
+ if (eglImage == EGL_NO_IMAGE) {
+ qWarning() << "EGL: Failed to create EGLImage:"
+ << ui::GetEGLErrorString(m_functions->eglGetError());
+ return;
+ }
+
+ int numPlanes = 0;
+ if (!m_functions->eglExportDMABUFImageQueryMESA(eglDisplay, eglImage, nullptr, &numPlanes,
+ modifiers))
+ qWarning() << "EGL: Failed to retrieve the pixel format of the buffer:"
+ << ui::GetEGLErrorString(m_functions->eglGetError());
+ Q_ASSERT(numPlanes == 1);
+
+ if (!m_functions->eglExportDMABUFImageMESA(eglDisplay, eglImage, fd, stride, offset))
+ qWarning() << "EGL: Failed to retrieve the dma_buf file descriptor:"
+ << ui::GetEGLErrorString(m_functions->eglGetError());
+
+ m_functions->eglDestroyImage(eglDisplay, eglImage);
+}
+
+bool EGLHelper::isDmaBufSupported()
+{
+ if (!m_isDmaBufSupported)
+ return false;
+
+ int fd = -1;
+ queryDmaBuf(2, 2, &fd, nullptr, nullptr, nullptr);
+ if (fd == -1) {
+ m_isDmaBufSupported = false;
+ return false;
+ }
+
+ close(fd);
+ return true;
+}
+#endif // QT_CONFIG(opengl) && defined(USE_OZONE)
+
QT_END_NAMESPACE
#if BUILDFLAG(IS_WIN)
namespace gl {
namespace init {
-scoped_refptr<GLContext> CreateGLContext(GLShareGroup* share_group,
- GLSurface* compatible_surface,
- const GLContextAttribs& attribs)
+scoped_refptr<GLContext> CreateGLContext(GLShareGroup *share_group,
+ GLSurface *compatible_surface,
+ const GLContextAttribs &attribs)
{
- scoped_refptr<GLContext> context;
- if (GetGLImplementation() == kGLImplementationDesktopGL) {
- context = new GLContextWGL(share_group);
+ switch (GetGLImplementation()) {
+ case kGLImplementationDesktopGLCoreProfile:
+ case kGLImplementationDesktopGL: {
+ scoped_refptr<GLContext> context = new GLContextWGL(share_group);
if (!context->Initialize(compatible_surface, attribs))
return nullptr;
return context;
- } else {
- context = new GLContextEGL(share_group);
}
-
- if (!GLContextHelper::initializeContext(context.get(), compatible_surface, attribs))
+ case kGLImplementationEGLANGLE:
+ case kGLImplementationEGLGLES2:
+ return InitializeGLContext(new GLContextEGL(share_group),
+ compatible_surface, attribs);
+ case kGLImplementationDisabled:
return nullptr;
-
- return context;
+ default:
+ break;
+ }
+ Q_UNREACHABLE();
+ return nullptr;
}
} // namespace init
diff --git a/src/core/ozone/gl_context_qt.h b/src/core/ozone/gl_context_qt.h
index f3ec219e6..bd1137053 100644
--- a/src/core/ozone/gl_context_qt.h
+++ b/src/core/ozone/gl_context_qt.h
@@ -5,10 +5,17 @@
#define GL_GL_CONTEXT_QT_H_
#include <QObject>
+#include <QtCore/qscopedpointer.h>
+#include <QtGui/qtgui-config.h>
+
#include "ui/gl/gl_context.h"
+#if QT_CONFIG(opengl) && defined(USE_OZONE)
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#endif
+
namespace gl {
-class GLContext;
class GLSurface;
}
@@ -39,6 +46,44 @@ private:
bool m_robustness = false;
};
+#if QT_CONFIG(opengl) && defined(USE_OZONE)
+#undef eglCreateImage
+#undef eglDestroyImage
+#undef eglExportDMABUFImageMESA
+#undef eglExportDMABUFImageQueryMESA
+#undef eglGetError
+#undef eglQueryString
+
+class EGLHelper
+{
+public:
+ struct EGLFunctions
+ {
+ EGLFunctions();
+
+ PFNEGLCREATEIMAGEPROC eglCreateImage;
+ PFNEGLDESTROYIMAGEPROC eglDestroyImage;
+ PFNEGLEXPORTDMABUFIMAGEMESAPROC eglExportDMABUFImageMESA;
+ PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC eglExportDMABUFImageQueryMESA;
+ PFNEGLGETERRORPROC eglGetError;
+ PFNEGLQUERYSTRINGPROC eglQueryString;
+ };
+
+ static EGLHelper *instance();
+
+ EGLFunctions *functions() const { return m_functions.get(); }
+ void queryDmaBuf(const int width, const int height, int *fd, int *stride, int *offset,
+ uint64_t *modifiers);
+ bool isDmaBufSupported();
+
+private:
+ EGLHelper();
+
+ QScopedPointer<EGLFunctions> m_functions;
+ bool m_isDmaBufSupported = false;
+};
+#endif // QT_CONFIG(opengl) && defined(USE_OZONE)
+
QT_END_NAMESPACE
#endif
diff --git a/src/core/ozone/gl_ozone_egl_qt.cpp b/src/core/ozone/gl_ozone_egl_qt.cpp
index c0348e833..26d11df31 100644
--- a/src/core/ozone/gl_ozone_egl_qt.cpp
+++ b/src/core/ozone/gl_ozone_egl_qt.cpp
@@ -6,57 +6,49 @@
#include "gl_ozone_egl_qt.h"
#include "gl_surface_egl_qt.h"
-#include "base/files/file_path.h"
-#include "base/native_library.h"
-#include "ui/gl/gl_context_egl.h"
-#include "ui/gl/gl_implementation.h"
+#include "media/gpu/buildflags.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_display.h"
#include "ui/gl/gl_surface.h"
-#include "ui/gl/init/gl_factory.h"
-#include "ui/gl/init/gl_initializer.h"
-
-#include <EGL/egl.h>
-#include <dlfcn.h>
+#include "ui/gl/gl_utils.h"
+#include "ui/ozone/common/native_pixmap_egl_binding.h"
namespace ui {
-bool GLOzoneEGLQt::LoadGLES2Bindings(const gl::GLImplementationParts & /*implementation*/)
+bool LoadQtEGLBindings()
{
- base::NativeLibrary eglgles2Library = dlopen(NULL, RTLD_LAZY);
- if (!eglgles2Library) {
- LOG(ERROR) << "Failed to open EGL/GLES2 context " << dlerror();
- return false;
- }
-
- gl::GLGetProcAddressProc get_proc_address =
- reinterpret_cast<gl::GLGetProcAddressProc>(
- base::GetFunctionPointerFromNativeLibrary(eglgles2Library,
- "eglGetProcAddress"));
- if (!get_proc_address) {
- // QTBUG-63341 most likely libgles2 not linked with libegl -> fallback to qpa
- get_proc_address =
- reinterpret_cast<gl::GLGetProcAddressProc>(GLContextHelper::getEglGetProcAddress());
- }
-
+ gl::GLGetProcAddressProc get_proc_address = reinterpret_cast<gl::GLGetProcAddressProc>(GLContextHelper::getEglGetProcAddress());
if (!get_proc_address) {
LOG(ERROR) << "eglGetProcAddress not found.";
- base::UnloadNativeLibrary(eglgles2Library);
return false;
}
-
gl::SetGLGetProcAddressProc(get_proc_address);
- gl::AddGLNativeLibrary(eglgles2Library);
return true;
}
-gl::GLDisplay *GLOzoneEGLQt::InitializeGLOneOffPlatform(uint64_t system_device_id)
+bool GLOzoneEGLQt::LoadGLES2Bindings(const gl::GLImplementationParts & /*implementation*/)
{
- return gl::GLSurfaceEGLQt::InitializeOneOff(system_device_id);
+ return LoadQtEGLBindings();
}
+gl::GLDisplay *GLOzoneEGLQt::InitializeGLOneOffPlatform(bool supports_angle,
+ std::vector<gl::DisplayType> init_displays,
+ gl::GpuPreference gpu_preference)
+{
+ if (auto display = gl::GLSurfaceEGLQt::InitializeOneOff(gpu_preference)) {
+ if (!static_cast<gl::GLDisplayEGL*>(display)->Initialize(supports_angle, std::move(init_displays), GetNativeDisplay())) {
+ LOG(ERROR) << "GLDisplayEGL::Initialize failed.";
+ return nullptr;
+ }
+ return display;
+ }
+ return nullptr;
+}
+
+
bool GLOzoneEGLQt::InitializeExtensionSettingsOneOffPlatform(gl::GLDisplay *display)
{
- Q_UNUSED(display);
- return gl::GLSurfaceEGLQt::InitializeExtensionSettingsOneOff();
+ return static_cast<gl::GLDisplayEGL*>(display)->InitializeExtensionSettings();
}
scoped_refptr<gl::GLSurface> GLOzoneEGLQt::CreateViewGLSurface(gl::GLDisplay* display, gfx::AcceleratedWidget window)
@@ -87,6 +79,24 @@ gl::EGLDisplayPlatform GLOzoneEGLQt::GetNativeDisplay()
return platform;
}
+bool GLOzoneEGLQt::CanImportNativePixmap()
+{
+ return gl::GLSurfaceEGL::GetGLDisplayEGL()->ext->b_EGL_EXT_image_dma_buf_import;
+}
+
+std::unique_ptr<NativePixmapGLBinding> GLOzoneEGLQt::ImportNativePixmap(
+ scoped_refptr<gfx::NativePixmap> pixmap,
+ gfx::BufferFormat plane_format,
+ gfx::BufferPlane plane,
+ gfx::Size plane_size,
+ const gfx::ColorSpace &color_space,
+ GLenum target,
+ GLuint texture_id)
+{
+ return NativePixmapEGLBinding::Create(pixmap, plane_format, plane, plane_size, color_space,
+ target, texture_id);
+}
+
} // namespace ui
#endif // defined(USE_OZONE)
diff --git a/src/core/ozone/gl_ozone_egl_qt.h b/src/core/ozone/gl_ozone_egl_qt.h
index 4619fc714..7ac55979a 100644
--- a/src/core/ozone/gl_ozone_egl_qt.h
+++ b/src/core/ozone/gl_ozone_egl_qt.h
@@ -12,7 +12,9 @@ namespace ui {
class GLOzoneEGLQt : public GLOzoneEGL {
public:
- gl::GLDisplay *InitializeGLOneOffPlatform(uint64_t system_device_id) override;
+ gl::GLDisplay *InitializeGLOneOffPlatform(bool supports_angle,
+ std::vector<gl::DisplayType> init_displays,
+ gl::GpuPreference gpu_preference) override;
bool InitializeExtensionSettingsOneOffPlatform(gl::GLDisplay *display) override;
scoped_refptr<gl::GLSurface> CreateViewGLSurface(
gl::GLDisplay *display,
@@ -20,6 +22,15 @@ public:
scoped_refptr<gl::GLSurface> CreateOffscreenGLSurface(
gl::GLDisplay *display,
const gfx::Size &size) override;
+ bool CanImportNativePixmap() override;
+ std::unique_ptr<NativePixmapGLBinding> ImportNativePixmap(
+ scoped_refptr<gfx::NativePixmap> pixmap,
+ gfx::BufferFormat plane_format,
+ gfx::BufferPlane plane,
+ gfx::Size plane_size,
+ const gfx::ColorSpace &color_space,
+ GLenum target,
+ GLuint texture_id) override;
protected:
// Returns native platform display handle. This is used to obtain the EGL
diff --git a/src/core/ozone/gl_ozone_glx_qt.cpp b/src/core/ozone/gl_ozone_glx_qt.cpp
index c610862f6..23ba92ea4 100644
--- a/src/core/ozone/gl_ozone_glx_qt.cpp
+++ b/src/core/ozone/gl_ozone_glx_qt.cpp
@@ -9,15 +9,20 @@
#include "gl_ozone_glx_qt.h"
#include "gl_surface_glx_qt.h"
#include "gl_context_qt.h"
+
+#include "media/gpu/buildflags.h"
#include "ui/gl/gl_context_glx.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_glx_api_implementation.h"
+#include "ui/gl/presenter.h"
+
#include <dlfcn.h>
namespace ui {
-gl::GLDisplay *GLOzoneGLXQt::InitializeGLOneOffPlatform(uint64_t system_device_id) {
- return gl::GLSurfaceGLXQt::InitializeOneOff(system_device_id);
+gl::GLDisplay *GLOzoneGLXQt::InitializeGLOneOffPlatform(bool, std::vector<gl::DisplayType>, gl::GpuPreference preference)
+{
+ return gl::GLSurfaceGLXQt::InitializeOneOff(preference);
}
bool GLOzoneGLXQt::InitializeStaticGLBindings(
@@ -87,7 +92,7 @@ scoped_refptr<gl::GLSurface> GLOzoneGLXQt::CreateViewGLSurface(
return nullptr;
}
-scoped_refptr<gl::GLSurface> GLOzoneGLXQt::CreateSurfacelessViewGLSurface(
+scoped_refptr<gl::Presenter> GLOzoneGLXQt::CreateSurfacelessViewGLSurface(
gl::GLDisplay* display,
gfx::AcceleratedWidget window) {
return nullptr;
@@ -109,8 +114,8 @@ bool GLOzoneGLXQt::CanImportNativePixmap()
}
std::unique_ptr<ui::NativePixmapGLBinding> GLOzoneGLXQt::ImportNativePixmap(
- scoped_refptr<gfx::NativePixmap>, gfx::BufferFormat, gfx::BufferPlane,
- gfx::Size, const gfx::ColorSpace&, GLenum, GLuint)
+ scoped_refptr<gfx::NativePixmap> pixmap, gfx::BufferFormat plane_format, gfx::BufferPlane plane,
+ gfx::Size plane_size, const gfx::ColorSpace &, GLenum target, GLuint texture_id)
{
return nullptr;
}
diff --git a/src/core/ozone/gl_ozone_glx_qt.h b/src/core/ozone/gl_ozone_glx_qt.h
index 777de352e..4df26ba71 100644
--- a/src/core/ozone/gl_ozone_glx_qt.h
+++ b/src/core/ozone/gl_ozone_glx_qt.h
@@ -15,7 +15,7 @@ public:
GLOzoneGLXQt() {}
~GLOzoneGLXQt() override {}
- gl::GLDisplay *InitializeGLOneOffPlatform(uint64_t system_device_id) override;
+ gl::GLDisplay *InitializeGLOneOffPlatform(bool, std::vector<gl::DisplayType>, gl::GpuPreference) override;
bool InitializeStaticGLBindings(const gl::GLImplementationParts &implementation) override;
bool InitializeExtensionSettingsOneOffPlatform(gl::GLDisplay *display) override;
void ShutdownGL(gl::GLDisplay *display) override;
@@ -28,7 +28,7 @@ public:
bool CanImportNativePixmap() override;
std::unique_ptr<ui::NativePixmapGLBinding> ImportNativePixmap(
scoped_refptr<gfx::NativePixmap>, gfx::BufferFormat, gfx::BufferPlane,
- gfx::Size, const gfx::ColorSpace&, GLenum, GLuint) override;
+ gfx::Size, const gfx::ColorSpace &, GLenum, GLuint) override;
scoped_refptr<gl::GLContext> CreateGLContext(
gl::GLShareGroup* share_group,
@@ -39,7 +39,7 @@ public:
gl::GLDisplay* display,
gfx::AcceleratedWidget window) override;
- scoped_refptr<gl::GLSurface> CreateSurfacelessViewGLSurface(
+ scoped_refptr<gl::Presenter> CreateSurfacelessViewGLSurface(
gl::GLDisplay* display,
gfx::AcceleratedWidget window) override;
diff --git a/src/core/ozone/gl_share_context_qt.cpp b/src/core/ozone/gl_share_context_qt.cpp
index 1ed5a48e4..b1c5e201f 100644
--- a/src/core/ozone/gl_share_context_qt.cpp
+++ b/src/core/ozone/gl_share_context_qt.cpp
@@ -5,14 +5,13 @@
#include <QtGui/qtgui-config.h>
#include <qpa/qplatformnativeinterface.h>
+#include "ui/gl/gl_context_egl.h"
+#include "ui/gl/gl_implementation.h"
+
#if QT_CONFIG(opengl)
#include <QtGui/qopenglcontext_platform.h>
#include <QOpenGLContext>
#include <QOpenGLExtraFunctions>
-
-#if defined(Q_OS_MACOS)
-#include "macos_context_type_helper.h"
-#endif // defined(Q_OS_MACOS)
#endif // QT_CONFIG(opengl)
namespace QtWebEngineCore {
@@ -22,9 +21,7 @@ QtShareGLContext::QtShareGLContext(QOpenGLContext *context)
{
#if QT_CONFIG(opengl)
#if defined(Q_OS_MACOS)
- auto *mac_ctx = context->nativeInterface<QNativeInterface::QCocoaGLContext>();
- if (mac_ctx)
- m_handle = cglContext(mac_ctx->nativeContext());
+ qFatal("macOS only support using ANGLE.");
#endif
#if defined(Q_OS_WIN)
auto *win_ctx = context->nativeInterface<QNativeInterface::QWGLContext>();
@@ -42,7 +39,7 @@ QtShareGLContext::QtShareGLContext(QOpenGLContext *context)
m_handle = (void *)egl_ctx->nativeContext();
#endif
if (!m_handle)
- qFatal("Could not get handle for shared contex");
+ qFatal("Could not get handle for shared context.");
#endif // QT_CONFIG(opengl)
}
@@ -59,17 +56,22 @@ unsigned int QtShareGLContext::CheckStickyGraphicsResetStatusImpl()
void ShareGroupQt::AboutToAddFirstContext()
{
+ if (gl::GetGLImplementation() == gl::kGLImplementationEGLANGLE) {
+ m_shareContextQt = new gl::GLContextEGL(nullptr);
+ return;
+ }
+
#if QT_CONFIG(opengl)
// This currently has to be setup by ::main in all applications using QQuickWebEngineView with
// delegated rendering.
QOpenGLContext *shareContext = QOpenGLContext::globalShareContext();
if (!shareContext) {
qFatal("QWebEngine: OpenGL resource sharing is not set up in QtQuick. Please make sure to "
- "call QtWebEngineCore::initialize() in your main() function before QCoreApplication is "
- "created.");
+ "call QtWebEngineQuick::initialize() in your main() function before "
+ "QCoreApplication is created.");
}
m_shareContextQt = new QtShareGLContext(shareContext);
-#endif
+#endif // QT_CONFIG(opengl)
}
} // namespace
diff --git a/src/core/ozone/gl_share_context_qt.h b/src/core/ozone/gl_share_context_qt.h
index ba66b222c..89be00421 100644
--- a/src/core/ozone/gl_share_context_qt.h
+++ b/src/core/ozone/gl_share_context_qt.h
@@ -57,7 +57,7 @@ public:
void AboutToAddFirstContext() override;
private:
- scoped_refptr<QtShareGLContext> m_shareContextQt;
+ scoped_refptr<gl::GLContext> m_shareContextQt;
};
} // namespace
#endif
diff --git a/src/core/ozone/gl_surface_egl_qt.cpp b/src/core/ozone/gl_surface_egl_qt.cpp
index 7f00ea6ed..a0c120ac6 100644
--- a/src/core/ozone/gl_surface_egl_qt.cpp
+++ b/src/core/ozone/gl_surface_egl_qt.cpp
@@ -12,79 +12,14 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_display.h"
#include "ui/gl/gl_display_manager.h"
-#include "ui/gl/gl_surface_egl.h"
#include "ui/gl/init/gl_factory.h"
-#if !BUILDFLAG(IS_MAC)
-// From ANGLE's egl/eglext.h.
-#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
-#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
-#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
-#endif
+#if !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
using ui::GetLastEGLErrorString;
namespace gl {
-bool GLDisplayEGL::InitializeExtensionSettings()
-{
- return GLSurfaceEGLQt::InitializeExtensionSettingsOneOff();
-}
-
-GLDisplayEGL *GLDisplayEGL::GetDisplayForCurrentContext()
-{
- GLContext *context = GLContext::GetCurrent();
- return context ? context->GetGLDisplayEGL() : nullptr;
-}
-
-bool GLDisplayEGL::IsEGLSurfacelessContextSupported()
-{
- return GLSurfaceEGLQt::g_egl_surfaceless_context_supported;
-}
-
-bool GLDisplayEGL::IsEGLContextPrioritySupported()
-{
- return false;
-}
-
-bool GLDisplayEGL::Initialize(gl::EGLDisplayPlatform native_display)
-{
- auto glDisplay = GLSurfaceEGLQt::InitializeOneOff(0);
-
- if (glDisplay) {
- display_ = glDisplay->GetDisplay();
- native_display_ = native_display;
- }
-
- return glDisplay;
-}
-
-bool GLDisplayEGL::IsAndroidNativeFenceSyncSupported()
-{
- return false;
-}
-
-// static
-GLDisplayEGL *GLSurfaceEGL::GetGLDisplayEGL()
-{
- return GLDisplayManagerEGL::GetInstance()->GetDisplay(GpuPreference::kDefault);
-}
-
-DisplayType GLDisplayEGL::GetDisplayType() const
-{
- return DisplayType::DEFAULT;
-}
-
-EGLDisplayPlatform GLDisplayEGL::GetNativeDisplay() const
-{
- return native_display_;
-}
-
-GLSurface *GLSurfaceEGL::createSurfaceless(gl::GLDisplayEGL *display, const gfx::Size& size)
-{
- return new GLSurfacelessQtEGL(display, size);
-}
-
bool GLSurfaceEGLQt::g_egl_surfaceless_context_supported = false;
bool GLSurfaceEGLQt::s_initialized = false;
@@ -99,12 +34,12 @@ GLSurfaceEGLQt::~GLSurfaceEGLQt()
Destroy();
}
-gl::GLDisplay *GLSurfaceEGLQt::InitializeOneOff(uint64_t system_device_id)
+gl::GLDisplay *GLSurfaceEGLQt::InitializeOneOff(gl::GpuPreference preference)
{
if (s_initialized)
return g_display;
- auto *egl_display = GLDisplayManagerEGL::GetInstance()->GetDisplay(system_device_id);
+ auto *egl_display = GLDisplayManagerEGL::GetInstance()->GetDisplay(preference);
g_display = egl_display;
egl_display->SetDisplay(GLContextHelper::getEGLDisplay());
if (!egl_display->GetDisplay()) {
@@ -123,7 +58,6 @@ gl::GLDisplay *GLSurfaceEGLQt::InitializeOneOff(uint64_t system_device_id)
return nullptr;
}
- g_client_extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
g_extensions = eglQueryString(egl_display->GetDisplay(), EGL_EXTENSIONS);
g_egl_surfaceless_context_supported = ExtensionsContain(g_extensions.c_str(), "EGL_KHR_surfaceless_context");
if (g_egl_surfaceless_context_supported) {
@@ -261,17 +195,4 @@ void* GLSurfacelessQtEGL::GetShareHandle()
}
} // namespace gl
-#endif // !BUILDFLAG(IS_MAC)
-
-namespace gl {
-
-std::string DisplayExtensionsEGL::GetPlatformExtensions(void*)
-{
- EGLDisplay display = GLContextHelper::getEGLDisplay();
- if (display == EGL_NO_DISPLAY)
- return "";
-
- const char* str = eglQueryString(display, EGL_EXTENSIONS);
- return str ? std::string(str) : "";
-}
-} // namespace gl
+#endif // !BUILDFLAG(IS_MAC) && !BUILDFLAG(IS_WIN)
diff --git a/src/core/ozone/gl_surface_egl_qt.h b/src/core/ozone/gl_surface_egl_qt.h
index 71992e700..d581f9079 100644
--- a/src/core/ozone/gl_surface_egl_qt.h
+++ b/src/core/ozone/gl_surface_egl_qt.h
@@ -6,7 +6,6 @@
#include "gl_surface_qt.h"
#include <EGL/egl.h>
-#include <EGL/eglext.h>
namespace gl {
@@ -16,7 +15,7 @@ class GLSurfaceEGLQt: public GLSurfaceQt {
public:
explicit GLSurfaceEGLQt(gl::GLDisplayEGL *display, const gfx::Size& size);
- static gl::GLDisplay *InitializeOneOff(uint64_t system_device_id);
+ static gl::GLDisplay *InitializeOneOff(gl::GpuPreference preference);
static bool InitializeExtensionSettingsOneOff();
bool Initialize(GLSurfaceFormat format) override;
diff --git a/src/core/ozone/gl_surface_glx_qt.cpp b/src/core/ozone/gl_surface_glx_qt.cpp
index 21de815a8..61c9ef9de 100644
--- a/src/core/ozone/gl_surface_glx_qt.cpp
+++ b/src/core/ozone/gl_surface_glx_qt.cpp
@@ -11,12 +11,14 @@
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_display.h"
#include "ui/gl/gl_display_manager.h"
+#include "ui/gl/gl_surface.h"
#include "ui/gl/gl_surface_glx.h"
namespace gl {
-void GLSurfaceGLX::ShutdownOneOff()
+static bool HasGLXExtension(const char *name)
{
+ return GLSurface::ExtensionsContain(GLSurfaceQt::g_extensions.c_str(), name);
}
bool GLSurfaceGLX::IsCreateContextSupported()
@@ -29,16 +31,6 @@ bool GLSurfaceGLX::IsCreateContextRobustnessSupported()
return GLContextHelper::isCreateContextRobustnessSupported() && HasGLXExtension("GLX_ARB_create_context_robustness");
}
-bool GLSurfaceGLX::IsEXTSwapControlSupported()
-{
- return HasGLXExtension("GLX_EXT_swap_control");
-}
-
-bool GLSurfaceGLX::IsMESASwapControlSupported()
-{
- return HasGLXExtension("GLX_MESA_swap_control");
-}
-
bool GLSurfaceGLX::IsCreateContextProfileSupported()
{
return false; // ExtensionsContain(g_extensions, "GLX_ARB_create_context_profile");
@@ -49,31 +41,11 @@ bool GLSurfaceGLX::IsCreateContextES2ProfileSupported()
return HasGLXExtension("GLX_ARB_create_context_es2_profile");
}
-bool GLSurfaceGLX::IsOMLSyncControlSupported()
-{
- return false; // ExtensionsContain(g_extensions, "GLX_OML_sync_control");
-}
-
-bool GLSurfaceGLX::HasGLXExtension(const char *name)
-{
- return ExtensionsContain(GLSurfaceQt::g_extensions.c_str(), name);
-}
-
-bool GLSurfaceGLX::IsTextureFromPixmapSupported()
-{
- return HasGLXExtension("GLX_EXT_texture_from_pixmap");
-}
-
bool GLSurfaceGLX::IsRobustnessVideoMemoryPurgeSupported()
{
return false;
}
-const char* GLSurfaceGLX::GetGLXExtensions()
-{
- return GLSurfaceQt::g_extensions.c_str();
-}
-
bool GLSurfaceGLXQt::s_initialized = false;
@@ -88,12 +60,12 @@ GLSurfaceGLXQt::~GLSurfaceGLXQt()
Destroy();
}
-GLDisplay *GLSurfaceGLXQt::InitializeOneOff(uint64_t system_device_id)
+GLDisplay *GLSurfaceGLXQt::InitializeOneOff(gl::GpuPreference preference)
{
if (s_initialized)
return g_display;
- g_display = GLDisplayManagerX11::GetInstance()->GetDisplay(system_device_id);
+ g_display = GLDisplayManagerX11::GetInstance()->GetDisplay(preference);
if (!g_display->GetDisplay()) {
LOG(ERROR) << "GLContextHelper::getXDisplay() failed.";
return nullptr;
@@ -121,7 +93,6 @@ GLDisplay *GLSurfaceGLXQt::InitializeOneOff(uint64_t system_device_id)
return g_display;
}
-
bool GLSurfaceGLXQt::InitializeExtensionSettingsOneOff()
{
if (!s_initialized)
@@ -133,11 +104,6 @@ bool GLSurfaceGLXQt::InitializeExtensionSettingsOneOff()
return true;
}
-bool GLSurfaceGLX::InitializeExtensionSettingsOneOff()
-{
- return GLSurfaceGLXQt::InitializeExtensionSettingsOneOff();
-}
-
bool GLSurfaceGLXQt::Initialize(GLSurfaceFormat format)
{
Q_ASSERT(!m_surfaceBuffer);
diff --git a/src/core/ozone/gl_surface_glx_qt.h b/src/core/ozone/gl_surface_glx_qt.h
index f81f6e9df..8cbf1fcf2 100644
--- a/src/core/ozone/gl_surface_glx_qt.h
+++ b/src/core/ozone/gl_surface_glx_qt.h
@@ -12,7 +12,7 @@ class GLSurfaceGLXQt: public GLSurfaceQt {
public:
explicit GLSurfaceGLXQt(const gfx::Size& size);
- static gl::GLDisplay *InitializeOneOff(uint64_t system_device_id);
+ static gl::GLDisplay *InitializeOneOff(gl::GpuPreference preference);
static bool InitializeExtensionSettingsOneOff();
bool Initialize(GLSurfaceFormat format) override;
diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp
index fad3ccc11..0cbe75cbd 100644
--- a/src/core/ozone/gl_surface_qt.cpp
+++ b/src/core/ozone/gl_surface_qt.cpp
@@ -1,4 +1,4 @@
-// Copyright (C) 2016 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
@@ -16,11 +16,15 @@
#if BUILDFLAG(IS_WIN)
#include "web_engine_context.h"
#include "ozone/gl_surface_wgl_qt.h"
-#include "ozone/gl_surface_egl_qt.h"
#include "gpu/ipc/service/image_transport_surface.h"
+#include "ui/gl/init/gl_display_initializer.h"
+#include "ui/gl/direct_composition_support.h"
+#include "ui/gl/gl_angle_util_win.h"
+#include "ui/gl/gl_display.h"
#include "ui/gl/gl_implementation.h"
-#include "ui/gl/direct_composition_surface_win.h"
+#include "ui/gl/gl_surface_egl.h"
+#include "ui/gl/gl_utils.h"
#include "ui/gl/vsync_provider_win.h"
#endif
@@ -29,7 +33,6 @@ namespace gl {
GLDisplay *GLSurfaceQt::g_display = nullptr;
void *GLSurfaceQt::g_config = nullptr;
-std::string GLSurfaceQt::g_client_extensions;
std::string GLSurfaceQt::g_extensions;
GLSurfaceQt::~GLSurfaceQt()
@@ -59,7 +62,7 @@ bool GLSurfaceQt::IsOffscreen()
return true;
}
-gfx::SwapResult GLSurfaceQt::SwapBuffers(PresentationCallback callback, FrameData data)
+gfx::SwapResult GLSurfaceQt::SwapBuffers(PresentationCallback callback, gfx::FrameData data)
{
LOG(ERROR) << "Attempted to call SwapBuffers on a pbuffer.";
Q_UNREACHABLE();
@@ -89,17 +92,31 @@ void* GLSurfaceQt::GetConfig()
#if BUILDFLAG(IS_WIN)
namespace init {
-gl::GLDisplay *InitializeGLOneOffPlatform(uint64_t system_device_id)
+gl::GLDisplay *InitializeGLOneOffPlatform(gl::GpuPreference gpu_preference)
{
VSyncProviderWin::InitializeOneOff();
- if (GetGLImplementation() == kGLImplementationEGLGLES2 || GetGLImplementation() == kGLImplementationEGLANGLE)
- return GLSurfaceEGLQt::InitializeOneOff(system_device_id);
-
if (GetGLImplementation() == kGLImplementationDesktopGL || GetGLImplementation() == kGLImplementationDesktopGLCoreProfile)
- return GLSurfaceWGLQt::InitializeOneOff(system_device_id);
+ return GLSurfaceWGLQt::InitializeOneOff(gpu_preference);
- return nullptr;
+ GLDisplayEGL *display = GetDisplayEGL(gpu_preference);
+ switch (GetGLImplementation()) {
+ case kGLImplementationEGLANGLE:
+ case kGLImplementationEGLGLES2:
+ if (!InitializeDisplay(display, EGLDisplayPlatform(GetDC(nullptr)))) {
+ LOG(ERROR) << "GLDisplayEGL::Initialize failed.";
+ return nullptr;
+ }
+ if (auto d3d11_device = QueryD3D11DeviceObjectFromANGLE())
+ InitializeDirectComposition(std::move(d3d11_device));
+ break;
+ case kGLImplementationMockGL:
+ case kGLImplementationStubGL:
+ break;
+ default:
+ NOTREACHED();
+ }
+ return display;
}
bool usingSoftwareDynamicGL()
@@ -125,21 +142,10 @@ CreateOffscreenGLSurfaceWithFormat(GLDisplay *display, const gfx::Size& size, GL
}
case kGLImplementationEGLANGLE:
case kGLImplementationEGLGLES2: {
- surface = new GLSurfaceEGLQt(static_cast<gl::GLDisplayEGL*>(display), size);
- if (surface->Initialize(format))
- return surface;
-
- // Surfaceless context will be used ONLY if pseudo surfaceless context
- // is not available since some implementations of surfaceless context
- // have problems. (e.g. QTBUG-57290)
- if (GLSurfaceEGLQt::g_egl_surfaceless_context_supported) {
- surface = new GLSurfacelessQtEGL(static_cast<gl::GLDisplayEGL*>(display), size);
- if (surface->Initialize(format))
- return surface;
- }
- LOG(ERROR) << "eglCreatePbufferSurface failed and surfaceless context not available";
- LOG(WARNING) << "Failed to create offscreen GL surface";
- break;
+ GLDisplayEGL *display_egl = display->GetAs<gl::GLDisplayEGL>();
+ if (display_egl->IsEGLSurfacelessContextSupported() && size.width() == 0 && size.height() == 0)
+ return InitializeGLSurfaceWithFormat(new SurfacelessEGL(display_egl, size), format);
+ return InitializeGLSurfaceWithFormat(new PbufferGLSurfaceEGL(display_egl, size), format);
}
default:
break;
@@ -150,9 +156,8 @@ CreateOffscreenGLSurfaceWithFormat(GLDisplay *display, const gfx::Size& size, GL
}
scoped_refptr<GLSurface>
-CreateViewGLSurface(gfx::AcceleratedWidget window)
+CreateViewGLSurface(GLDisplay *display, gfx::AcceleratedWidget window)
{
- QT_NOT_USED
return nullptr;
}
@@ -160,18 +165,4 @@ CreateViewGLSurface(gfx::AcceleratedWidget window)
#endif // BUILDFLAG(IS_WIN)
} // namespace gl
-#if BUILDFLAG(IS_WIN)
-namespace gpu {
-class GpuCommandBufferStub;
-class GpuChannelManager;
-scoped_refptr<gl::GLSurface> ImageTransportSurface::CreateNativeSurface(gl::GLDisplay *,
- base::WeakPtr<ImageTransportSurfaceDelegate>,
- SurfaceHandle, gl::GLSurfaceFormat)
-{
- QT_NOT_USED
- return scoped_refptr<gl::GLSurface>();
-}
-} // namespace gpu
-#endif // BUILDFLAG(IS_WIN)
-
#endif // !defined(Q_OS_MACOS)
diff --git a/src/core/ozone/gl_surface_qt.h b/src/core/ozone/gl_surface_qt.h
index 0ef8fbbca..1ae41a078 100644
--- a/src/core/ozone/gl_surface_qt.h
+++ b/src/core/ozone/gl_surface_qt.h
@@ -21,7 +21,7 @@ public:
GLDisplay *GetGLDisplay() override;
void *GetConfig() override;
bool IsOffscreen() override;
- gfx::SwapResult SwapBuffers(PresentationCallback callback, FrameData data) override;
+ gfx::SwapResult SwapBuffers(PresentationCallback callback, gfx::FrameData data) override;
gfx::Size GetSize() override;
GLSurfaceFormat GetFormat() override;
@@ -36,7 +36,6 @@ public:
static void* g_config;
static GLDisplay *g_display;
static std::string g_extensions;
- static std::string g_client_extensions;
};
} // namespace gl
diff --git a/src/core/ozone/gl_surface_wgl_qt.cpp b/src/core/ozone/gl_surface_wgl_qt.cpp
index 0788a04c1..db4aed884 100644
--- a/src/core/ozone/gl_surface_wgl_qt.cpp
+++ b/src/core/ozone/gl_surface_wgl_qt.cpp
@@ -20,10 +20,10 @@ GLSurfaceWGLQt::~GLSurfaceWGLQt()
Destroy();
}
-gl::GLDisplay *GLSurfaceWGLQt::InitializeOneOff(uint64_t system_device_id)
+gl::GLDisplay *GLSurfaceWGLQt::InitializeOneOff(gl::GpuPreference gpu_preference)
{
if (GLSurfaceWGL::InitializeOneOff())
- return GLDisplayManagerWGL::GetInstance()->GetDisplay(GpuPreference::kDefault);
+ return GLDisplayManagerWGL::GetInstance()->GetDisplay(gpu_preference);
return nullptr;
}
diff --git a/src/core/ozone/gl_surface_wgl_qt.h b/src/core/ozone/gl_surface_wgl_qt.h
index 5b671ebd9..6c590e46c 100644
--- a/src/core/ozone/gl_surface_wgl_qt.h
+++ b/src/core/ozone/gl_surface_wgl_qt.h
@@ -16,7 +16,7 @@ class GLSurfaceWGLQt: public GLSurfaceQt {
public:
explicit GLSurfaceWGLQt(const gfx::Size& size);
- static gl::GLDisplay *InitializeOneOff(uint64_t system_device_id);
+ static gl::GLDisplay *InitializeOneOff(gl::GpuPreference gpu_preference);
bool Initialize(GLSurfaceFormat format) override;
void Destroy() override;
diff --git a/src/core/ozone/ozone_extra.gni b/src/core/ozone/ozone_extra.gni
index a832f741a..191bb3787 100644
--- a/src/core/ozone/ozone_extra.gni
+++ b/src/core/ozone/ozone_extra.gni
@@ -17,3 +17,17 @@ ozone_external_platform_deps = []
# so that they get included into ozone_unittests.
# ozone_external_platform_test_deps = [ "platform/foo1:foo1_unitests", ... ]
ozone_external_platform_test_deps = []
+
+# If a platform has integration tests, the corresponding source_set can be
+# listed here so that they get included into ozone_integration_tests.
+ozone_external_platform_integration_test_deps = []
+
+# If a platform has test support files for ui, the corresponding source_set can
+# be listed here so that they get included into ui_test_support.
+# ozone_external_platform_ui_test_support_deps = [ "platform/foo1:ui_test_support", ... ]
+ozone_external_platform_ui_test_support_deps = []
+
+# If a platform has a test support for interactive_ui_tests, the corresponding
+# source_set can be listed here so that they can included into
+# interactive_ui_tests.
+ozone_external_interactive_ui_tests_deps = []
diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp
index 5b7e9b4d7..e8547fa87 100644
--- a/src/core/ozone/ozone_platform_qt.cpp
+++ b/src/core/ozone/ozone_platform_qt.cpp
@@ -5,19 +5,23 @@
#if defined(USE_OZONE)
#include "base/no_destructor.h"
+#include "base/task/thread_pool.h"
+#include "media/gpu/buildflags.h"
#include "ui/base/buildflags.h"
#include "ui/base/ime/input_method.h"
#include "ui/display/types/native_display_delegate.h"
#include "ui/events/ozone/layout/keyboard_layout_engine_manager.h"
#include "ui/events/ozone/layout/stub/stub_keyboard_layout_engine.h"
+#include "ui/gfx/linux/client_native_pixmap_dmabuf.h"
+#include "ui/gfx/linux/client_native_pixmap_factory_dmabuf.h"
#include "ui/ozone/common/bitmap_cursor_factory.h"
-#include "ui/ozone/common/stub_client_native_pixmap_factory.h"
#include "ui/ozone/common/stub_overlay_manager.h"
#include "ui/ozone/public/gpu_platform_support_host.h"
#include "ui/ozone/public/input_controller.h"
#include "ui/ozone/public/ozone_platform.h"
#include "ui/ozone/public/platform_screen.h"
#include "ui/ozone/public/system_input_injector.h"
+#include "ui/ozone/platform/wayland/gpu/wayland_gl_egl_utility.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
@@ -32,9 +36,14 @@
#include <X11/XKBlib.h>
#include <X11/extensions/XKBrules.h>
#include <filesystem>
+#endif // BUILDFLAG(USE_XKBCOMMON)
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
+#include "ui/ozone/platform/x11/gl_egl_utility_x11.h"
extern void *GetQtXDisplay();
-#endif // BUILDFLAG(USE_XKBCOMMON)
+#endif
namespace ui {
@@ -56,6 +65,19 @@ public:
std::unique_ptr<InputMethod> CreateInputMethod(ImeKeyEventDispatcher *ime_key_event_dispatcher, gfx::AcceleratedWidget widget) override;
std::unique_ptr<ui::PlatformScreen> CreateScreen() override { return nullptr; }
const PlatformProperties &GetPlatformProperties() override;
+ PlatformGLEGLUtility *GetPlatformGLEGLUtility() override;
+
+ const PlatformRuntimeProperties &GetPlatformRuntimeProperties() override
+ {
+ static OzonePlatform::PlatformRuntimeProperties properties;
+ if (has_initialized_gpu()) {
+ // This property is set when the GetPlatformRuntimeProperties is
+ // called on the gpu process side.
+ properties.supports_native_pixmaps = surface_factory_ozone_->SupportsNativePixmaps();
+ }
+ return properties;
+ }
+ bool IsNativePixmapConfigSupported(gfx::BufferFormat format, gfx::BufferUsage usage) const override;
private:
bool InitializeUI(const ui::OzonePlatform::InitParams &) override;
@@ -74,6 +96,7 @@ private:
XkbEvdevCodes m_xkbEvdevCodeConverter;
#endif
std::unique_ptr<KeyboardLayoutEngine> m_keyboardLayoutEngine;
+ std::unique_ptr<PlatformGLEGLUtility> gl_egl_utility_;
};
@@ -87,7 +110,9 @@ const ui::OzonePlatform::PlatformProperties &OzonePlatformQt::GetPlatformPropert
static bool initialized = false;
if (!initialized) {
properties->fetch_buffer_formats_for_gmb_on_gpu = true;
-
+#if BUILDFLAG(USE_VAAPI)
+ properties->supports_vaapi = true;
+#endif
initialized = true;
}
@@ -205,9 +230,19 @@ bool OzonePlatformQt::InitializeUI(const ui::OzonePlatform::InitParams &)
return true;
}
-void OzonePlatformQt::InitializeGPU(const ui::OzonePlatform::InitParams &)
+void OzonePlatformQt::InitializeGPU(const ui::OzonePlatform::InitParams &params)
{
surface_factory_ozone_.reset(new QtWebEngineCore::SurfaceFactoryQt());
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (params.enable_native_gpu_memory_buffers) {
+ base::ThreadPool::PostTask(FROM_HERE,
+ base::BindOnce([]()
+ {
+ ui::GpuMemoryBufferSupportX11::GetInstance();
+ }));
+ }
+#endif
}
std::unique_ptr<InputMethod> OzonePlatformQt::CreateInputMethod(ImeKeyEventDispatcher *, gfx::AcceleratedWidget)
@@ -216,13 +251,31 @@ std::unique_ptr<InputMethod> OzonePlatformQt::CreateInputMethod(ImeKeyEventDispa
return nullptr;
}
+bool OzonePlatformQt::IsNativePixmapConfigSupported(gfx::BufferFormat format, gfx::BufferUsage usage) const
+{
+ return gfx::ClientNativePixmapDmaBuf::IsConfigurationSupported(format, usage);
+}
+
+PlatformGLEGLUtility *OzonePlatformQt::GetPlatformGLEGLUtility()
+{
+ if (!gl_egl_utility_) {
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (GetQtXDisplay())
+ gl_egl_utility_ = std::make_unique<GLEGLUtilityX11>();
+ else
+#endif
+ gl_egl_utility_ = std::make_unique<WaylandGLEGLUtility>();
+ }
+ return gl_egl_utility_.get();
+}
+
} // namespace
OzonePlatform* CreateOzonePlatformQt() { return new OzonePlatformQt; }
-gfx::ClientNativePixmapFactory* CreateClientNativePixmapFactoryQt()
+gfx::ClientNativePixmapFactory *CreateClientNativePixmapFactoryQt()
{
- return CreateStubClientNativePixmapFactory();
+ return gfx::CreateClientNativePixmapFactoryDmabuf();
}
} // namespace ui
diff --git a/src/core/ozone/platform_window_qt.cpp b/src/core/ozone/platform_window_qt.cpp
index fe8a715ce..4923f0f88 100644
--- a/src/core/ozone/platform_window_qt.cpp
+++ b/src/core/ozone/platform_window_qt.cpp
@@ -3,7 +3,7 @@
#if defined(USE_OZONE)
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "ozone/platform_window_qt.h"
#include "ui/base/cursor/platform_cursor.h"
#include "ui/events/ozone/events_ozone.h"
diff --git a/src/core/ozone/platform_window_qt.h b/src/core/ozone/platform_window_qt.h
index 0d1743f68..c025102bb 100644
--- a/src/core/ozone/platform_window_qt.h
+++ b/src/core/ozone/platform_window_qt.h
@@ -33,7 +33,7 @@ public:
void SetCapture() override { }
void ReleaseCapture() override { }
bool HasCapture() const override { return false; }
- void ToggleFullscreen() override { }
+ void SetFullscreen(bool, int64_t) override { }
void Maximize() override { }
void Minimize() override { }
void Restore() override { }
diff --git a/src/core/ozone/surface_factory_qt.cpp b/src/core/ozone/surface_factory_qt.cpp
index 13c1a7b11..204f4d62d 100644
--- a/src/core/ozone/surface_factory_qt.cpp
+++ b/src/core/ozone/surface_factory_qt.cpp
@@ -1,16 +1,28 @@
-// Copyright (C) 2017 The Qt Company Ltd.
+// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#if defined(USE_OZONE)
#include "surface_factory_qt.h"
+#include "qtwebenginecoreglobal_p.h"
#include "ozone/gl_context_qt.h"
#include "ozone/gl_ozone_egl_qt.h"
-#if defined(USE_GLX)
+
+#include "media/gpu/buildflags.h"
+#include "ui/gfx/linux/drm_util_linux.h"
+#include "ui/gfx/linux/gbm_buffer.h"
+#include "ui/gfx/linux/native_pixmap_dmabuf.h"
+#include "ui/gl/egl_util.h"
+#include "ui/ozone/buildflags.h"
+
+#include <QDebug>
+#include <QtGui/qtgui-config.h>
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
#include "ozone/gl_ozone_glx_qt.h"
-#endif
-#include "qtwebenginecoreglobal_p.h"
+#include "ui/gfx/linux/gpu_memory_buffer_support_x11.h"
+#endif
#if QT_CONFIG(webengine_vulkan)
#include "compositor/vulkan_implementation_qt.h"
@@ -20,7 +32,7 @@ namespace QtWebEngineCore {
SurfaceFactoryQt::SurfaceFactoryQt()
{
-#if defined(USE_GLX)
+#if BUILDFLAG(OZONE_PLATFORM_X11)
if (GLContextHelper::getGlxPlatformInterface()) {
m_impl = { gl::GLImplementationParts(gl::kGLImplementationDesktopGL),
gl::GLImplementationParts(gl::kGLImplementationDisabled) };
@@ -28,8 +40,8 @@ SurfaceFactoryQt::SurfaceFactoryQt()
} else
#endif
if (GLContextHelper::getEglPlatformInterface()) {
- m_impl = { gl::GLImplementationParts(gl::kGLImplementationDesktopGL),
- gl::GLImplementationParts(gl::kGLImplementationEGLGLES2),
+ m_impl = { gl::GLImplementationParts(gl::kGLImplementationEGLGLES2),
+ gl::GLImplementationParts(gl::kGLImplementationDesktopGL),
gl::GLImplementationParts(gl::kGLImplementationDisabled) };
m_ozone.reset(new ui::GLOzoneEGLQt());
} else {
@@ -59,6 +71,191 @@ SurfaceFactoryQt::CreateVulkanImplementation(bool /*allow_protected_memory*/,
}
#endif
+bool SurfaceFactoryQt::CanCreateNativePixmapForFormat(gfx::BufferFormat format)
+{
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (GLContextHelper::getGlxPlatformInterface())
+ return ui::GpuMemoryBufferSupportX11::GetInstance()->CanCreateNativePixmapForFormat(format);
+#endif
+
+ if (GLContextHelper::getEglPlatformInterface())
+ return ui::SurfaceFactoryOzone::CanCreateNativePixmapForFormat(format);
+
+ return false;
+}
+
+scoped_refptr<gfx::NativePixmap> SurfaceFactoryQt::CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ gpu::VulkanDeviceQueue *device_queue,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ absl::optional<gfx::Size> framebuffer_size)
+{
+ Q_ASSERT(SupportsNativePixmaps());
+
+#if QT_CONFIG(opengl)
+ if (framebuffer_size && !gfx::Rect(size).Contains(gfx::Rect(*framebuffer_size)))
+ return nullptr;
+
+ gfx::NativePixmapHandle handle;
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (GLContextHelper::getGlxPlatformInterface()) {
+ auto gbmBuffer =
+ ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBuffer(format, size, usage);
+ if (!gbmBuffer)
+ qFatal("Failed to create GBM buffer for GLX.");
+ handle = gbmBuffer->ExportHandle();
+ }
+#endif
+
+ if (GLContextHelper::getEglPlatformInterface()) {
+ int fd = -1;
+ int stride;
+ int offset;
+ uint64_t modifiers;
+ EGLHelper::instance()->queryDmaBuf(size.width(), size.height(), &fd, &stride, &offset,
+ &modifiers);
+ if (fd == -1)
+ qFatal("Failed to query DRM FD for EGL.");
+
+ const uint64_t planeSize = uint64_t(size.width()) * size.height() * 4;
+ gfx::NativePixmapPlane plane(stride, offset, planeSize, base::ScopedFD(::dup(fd)));
+
+ handle.planes.push_back(std::move(plane));
+ handle.modifier = modifiers;
+ }
+
+ return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(handle));
+#else
+ return nullptr;
+#endif // QT_CONFIG(opengl)
+}
+
+void SurfaceFactoryQt::CreateNativePixmapAsync(
+ gfx::AcceleratedWidget widget,
+ gpu::VulkanDeviceQueue *device_queue,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ NativePixmapCallback callback)
+{
+ Q_ASSERT(SupportsNativePixmaps());
+ // CreateNativePixmap is non-blocking operation. Thus, it is safe to call it
+ // and return the result with the provided callback.
+ std::move(callback).Run(CreateNativePixmap(widget, device_queue, size, format, usage));
+}
+
+scoped_refptr<gfx::NativePixmap>
+SurfaceFactoryQt::CreateNativePixmapFromHandle(
+ gfx::AcceleratedWidget /*widget*/,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::NativePixmapHandle handle)
+{
+ Q_ASSERT(SupportsNativePixmaps());
+
+#if QT_CONFIG(opengl)
+ gfx::NativePixmapHandle bufferHandle;
+
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (GLContextHelper::getGlxPlatformInterface()) {
+ auto gbmBuffer = ui::GpuMemoryBufferSupportX11::GetInstance()->CreateBufferFromHandle(
+ size, format, std::move(handle));
+ if (!gbmBuffer)
+ qFatal("Failed to create GBM buffer for GLX.");
+ bufferHandle = gbmBuffer->ExportHandle();
+ }
+#endif
+
+ if (GLContextHelper::getEglPlatformInterface()) {
+ const size_t numPlanes = handle.planes.size();
+ const uint32_t fourccFormat = ui::GetFourCCFormatFromBufferFormat(format);
+
+ std::vector<EGLAttrib> attrs;
+ attrs.push_back(EGL_WIDTH);
+ attrs.push_back(size.width());
+ attrs.push_back(EGL_HEIGHT);
+ attrs.push_back(size.height());
+ attrs.push_back(EGL_LINUX_DRM_FOURCC_EXT);
+ attrs.push_back(fourccFormat);
+ for (size_t planeIndex = 0; planeIndex < numPlanes; ++planeIndex) {
+ attrs.push_back(EGL_DMA_BUF_PLANE0_FD_EXT + planeIndex * 3);
+ attrs.push_back(handle.planes[planeIndex].fd.get());
+ attrs.push_back(EGL_DMA_BUF_PLANE0_OFFSET_EXT + planeIndex * 3);
+ attrs.push_back(handle.planes[planeIndex].offset);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_PITCH_EXT + planeIndex * 3);
+ attrs.push_back(handle.planes[planeIndex].stride);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT + planeIndex * 2);
+ attrs.push_back(handle.modifier & 0xffffffff);
+ attrs.push_back(EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT + planeIndex * 2);
+ attrs.push_back(handle.modifier >> 32);
+ }
+ attrs.push_back(EGL_NONE);
+
+ EGLDisplay eglDisplay = GLContextHelper::getEGLDisplay();
+ EGLHelper *eglHelper = EGLHelper::instance();
+ auto *eglFun = eglHelper->functions();
+
+ EGLImage eglImage =
+ eglFun->eglCreateImage(eglDisplay, EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT,
+ (EGLClientBuffer)NULL, attrs.data());
+ if (eglImage == EGL_NO_IMAGE_KHR) {
+ qFatal() << "Failed to import EGLImage:"
+ << ui::GetEGLErrorString(eglFun->eglGetError());
+ }
+
+ Q_ASSERT(numPlanes <= 3);
+ int fds[3];
+ int strides[3];
+ int offsets[3];
+ if (!eglFun->eglExportDMABUFImageMESA(eglDisplay, eglImage, fds, strides, offsets)) {
+ qFatal() << "Failed to export EGLImage:"
+ << ui::GetEGLErrorString(eglFun->eglGetError());
+ }
+
+ bufferHandle.modifier = handle.modifier;
+ for (size_t i = 0; i < numPlanes; ++i) {
+ int fd = fds[i];
+ int stride = strides[i];
+ int offset = offsets[i];
+ int size = handle.planes[i].size;
+
+ if (fd == -1) {
+ fd = fds[0];
+ stride = handle.planes[i].stride;
+ offset = handle.planes[i].offset;
+ }
+
+ gfx::NativePixmapPlane plane(stride, offset, size, base::ScopedFD(::dup(fd)));
+ bufferHandle.planes.push_back(std::move(plane));
+ }
+
+ eglFun->eglDestroyImage(eglDisplay, eglImage);
+ }
+
+ return base::MakeRefCounted<gfx::NativePixmapDmaBuf>(size, format, std::move(bufferHandle));
+#else
+ return nullptr;
+#endif // QT_CONFIG(opengl)
+}
+
+bool SurfaceFactoryQt::SupportsNativePixmaps() const
+{
+#if QT_CONFIG(opengl)
+#if BUILDFLAG(OZONE_PLATFORM_X11)
+ if (GLContextHelper::getGlxPlatformInterface())
+ return ui::GpuMemoryBufferSupportX11::GetInstance()->has_gbm_device();
+#endif // BUILDFLAG(OZONE_PLATFORM_X11)
+
+ if (GLContextHelper::getEglPlatformInterface())
+ return EGLHelper::instance()->isDmaBufSupported();
+#endif // QT_CONFIG(opengl)
+
+ return false;
+}
+
} // namespace QtWebEngineCore
#endif // defined(USE_OZONE)
diff --git a/src/core/ozone/surface_factory_qt.h b/src/core/ozone/surface_factory_qt.h
index bfcfa014b..07d7337ac 100644
--- a/src/core/ozone/surface_factory_qt.h
+++ b/src/core/ozone/surface_factory_qt.h
@@ -20,6 +20,28 @@ public:
std::unique_ptr<gpu::VulkanImplementation>
CreateVulkanImplementation(bool allow_protected_memory, bool enforce_protected_memory) override;
#endif
+ bool CanCreateNativePixmapForFormat(gfx::BufferFormat format) override;
+ scoped_refptr<gfx::NativePixmap> CreateNativePixmap(
+ gfx::AcceleratedWidget widget,
+ gpu::VulkanDeviceQueue* device_queue,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ absl::optional<gfx::Size> framebuffer_size = absl::nullopt) override;
+ void CreateNativePixmapAsync(gfx::AcceleratedWidget widget,
+ gpu::VulkanDeviceQueue* device_queue,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::BufferUsage usage,
+ NativePixmapCallback callback) override;
+ scoped_refptr<gfx::NativePixmap> CreateNativePixmapFromHandle(
+ gfx::AcceleratedWidget widget,
+ gfx::Size size,
+ gfx::BufferFormat format,
+ gfx::NativePixmapHandle handle) override;
+
+ bool SupportsNativePixmaps() const;
+
private:
std::vector<gl::GLImplementationParts> m_impl;
std::unique_ptr<ui::GLOzone> m_ozone;
diff --git a/src/core/pdf_util_qt.cpp b/src/core/pdf_util_qt.cpp
new file mode 100644
index 000000000..9503f5910
--- /dev/null
+++ b/src/core/pdf_util_qt.cpp
@@ -0,0 +1,92 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.Chromium file.
+
+#include "pdf_util_qt.h"
+
+#include <QtGlobal>
+
+#include "base/check.h"
+#include "chrome/common/webui_url_constants.h"
+#include "content/public/browser/render_frame_host.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "extensions/buildflags/buildflags.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+#include "extensions/common/constants.h"
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
+
+namespace QtWebEngineCore {
+
+bool IsPdfExtensionOrigin(const url::Origin &origin)
+{
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ return origin.scheme() == extensions::kExtensionScheme
+ && origin.host() == extension_misc::kPdfExtensionId;
+#else
+ Q_UNUSED(origin);
+ return false;
+#endif
+}
+
+bool IsPdfInternalPluginAllowedOrigin(const url::Origin &origin)
+{
+ if (IsPdfExtensionOrigin(origin))
+ return true;
+
+ // Allow embedding the internal PDF plugin in chrome://print.
+ if (origin == url::Origin::Create(GURL(chrome::kChromeUIPrintURL)))
+ return true;
+
+ // Only allow the PDF plugin in the known, trustworthy origins that are
+ // allowlisted above. See also https://crbug.com/520422 and
+ // https://crbug.com/1027173.
+ return false;
+}
+
+content::RenderFrameHost *GetFullPagePlugin(content::WebContents *contents)
+{
+ content::RenderFrameHost *full_page_plugin = nullptr;
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ contents->ForEachRenderFrameHostWithAction([&full_page_plugin](content::RenderFrameHost *rfh) {
+ auto* guest_view = extensions::MimeHandlerViewGuest::FromRenderFrameHost(rfh);
+ if (guest_view && guest_view->is_full_page_plugin()) {
+ DCHECK_EQ(guest_view->GetGuestMainFrame(), rfh);
+ full_page_plugin = rfh;
+ return content::RenderFrameHost::FrameIterationAction::kStop;
+ }
+ return content::RenderFrameHost::FrameIterationAction::kContinue;
+ });
+#endif // BUILDFLAG(ENABLE_EXTENSIONS)
+ return full_page_plugin;
+}
+
+content::RenderFrameHost *FindPdfChildFrame(content::RenderFrameHost *rfh)
+{
+ if (!rfh)
+ return nullptr;
+
+ if (!IsPdfExtensionOrigin(rfh->GetLastCommittedOrigin()))
+ return nullptr;
+
+ content::RenderFrameHost *pdf_rfh = nullptr;
+ rfh->ForEachRenderFrameHost([&pdf_rfh](content::RenderFrameHost *rfh) {
+ if (!rfh->GetProcess()->IsPdf())
+ return;
+
+ DCHECK(IsPdfExtensionOrigin(rfh->GetParent()->GetLastCommittedOrigin()));
+ DCHECK(!pdf_rfh);
+ pdf_rfh = rfh;
+ });
+
+ return pdf_rfh;
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/pdf_util_qt.h b/src/core/pdf_util_qt.h
new file mode 100644
index 000000000..5ee211800
--- /dev/null
+++ b/src/core/pdf_util_qt.h
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// Copyright 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE.Chromium file.
+
+#ifndef PDF_UTIL_QT_H
+#define PDF_UTIL_QT_H
+
+namespace content {
+class RenderFrameHost;
+class WebContents;
+} // namespace content
+
+namespace url {
+class Origin;
+} // namespace url
+
+namespace QtWebEngineCore {
+
+// from chrome/common/pdf_util.cc:
+constexpr char kPDFMimeType[] = "application/pdf";
+
+bool IsPdfExtensionOrigin(const url::Origin &origin);
+bool IsPdfInternalPluginAllowedOrigin(const url::Origin &origin);
+
+// from chrome/browser/pdf/pdf_frame_util.cc:
+content::RenderFrameHost *GetFullPagePlugin(content::WebContents *contents);
+content::RenderFrameHost *FindPdfChildFrame(content::RenderFrameHost *rfh);
+
+} // namespace QtWebEngineCore
+
+#endif // PDF_UTIL_QT_H
diff --git a/src/core/permission_manager_qt.cpp b/src/core/permission_manager_qt.cpp
index 9d98c0592..b6e727ef8 100644
--- a/src/core/permission_manager_qt.cpp
+++ b/src/core/permission_manager_qt.cpp
@@ -25,15 +25,18 @@ static ProfileAdapter::PermissionType toQt(blink::PermissionType type)
return ProfileAdapter::AudioCapturePermission;
case blink::PermissionType::VIDEO_CAPTURE:
return ProfileAdapter::VideoCapturePermission;
+ // We treat these both as read/write since we do not currently have a
+ // ClipboardSanitizedWrite feature.
case blink::PermissionType::CLIPBOARD_READ_WRITE:
- return ProfileAdapter::ClipboardRead;
case blink::PermissionType::CLIPBOARD_SANITIZED_WRITE:
- return ProfileAdapter::ClipboardWrite;
+ return ProfileAdapter::ClipboardReadWrite;
case blink::PermissionType::NOTIFICATIONS:
return ProfileAdapter::NotificationPermission;
+ case blink::PermissionType::LOCAL_FONTS:
+ return ProfileAdapter::LocalFontsPermission;
case blink::PermissionType::ACCESSIBILITY_EVENTS:
case blink::PermissionType::CAMERA_PAN_TILT_ZOOM:
- case blink::PermissionType::WINDOW_PLACEMENT:
+ case blink::PermissionType::WINDOW_MANAGEMENT:
return ProfileAdapter::UnsupportedPermission;
case blink::PermissionType::MIDI_SYSEX:
case blink::PermissionType::PROTECTED_MEDIA_IDENTIFIER:
@@ -51,8 +54,8 @@ static ProfileAdapter::PermissionType toQt(blink::PermissionType type)
case blink::PermissionType::AR:
case blink::PermissionType::VR:
case blink::PermissionType::STORAGE_ACCESS_GRANT:
- case blink::PermissionType::LOCAL_FONTS:
case blink::PermissionType::DISPLAY_CAPTURE:
+ case blink::PermissionType::TOP_LEVEL_STORAGE_ACCESS:
case blink::PermissionType::NUM:
LOG(INFO) << "Unexpected unsupported permission type: " << static_cast<int>(type);
break;
@@ -65,6 +68,8 @@ static bool canRequestPermissionFor(ProfileAdapter::PermissionType type)
switch (type) {
case ProfileAdapter::GeolocationPermission:
case ProfileAdapter::NotificationPermission:
+ case ProfileAdapter::ClipboardReadWrite:
+ case ProfileAdapter::LocalFontsPermission:
return true;
default:
break;
@@ -84,6 +89,20 @@ static blink::mojom::PermissionStatus toBlink(ProfileAdapter::PermissionState re
}
}
+static blink::mojom::PermissionStatus getStatusFromSettings(blink::PermissionType type, WebEngineSettings *settings)
+{
+ switch (type) {
+ case blink::PermissionType::CLIPBOARD_READ_WRITE:
+ case blink::PermissionType::CLIPBOARD_SANITIZED_WRITE:
+ if (settings->testAttribute(QWebEngineSettings::JavascriptCanPaste)
+ && settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard))
+ return blink::mojom::PermissionStatus::GRANTED;
+ return blink::mojom::PermissionStatus::ASK;
+ default:
+ return blink::mojom::PermissionStatus::ASK;
+ }
+}
+
PermissionManagerQt::PermissionManagerQt()
: m_requestIdCount(0)
{
@@ -163,49 +182,12 @@ bool PermissionManagerQt::checkPermission(const QUrl &origin, ProfileAdapter::Pe
return m_permissions.contains(key) && m_permissions[key];
}
-void PermissionManagerQt::RequestPermission(blink::PermissionType permission,
- content::RenderFrameHost *frameHost,
- const GURL& requesting_origin,
- bool /*user_gesture*/,
- base::OnceCallback<void(blink::mojom::PermissionStatus)> callback)
-{
- if (requesting_origin.is_empty()) {
- std::move(callback).Run(blink::mojom::PermissionStatus::DENIED);
- return;
- }
-
- WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt *>(
- content::WebContents::FromRenderFrameHost(frameHost)->GetDelegate());
- Q_ASSERT(contentsDelegate);
-
- ProfileAdapter::PermissionType permissionType = toQt(permission);
- if (permissionType == ProfileAdapter::ClipboardRead) {
- WebEngineSettings *settings = contentsDelegate->webEngineSettings();
- if (settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard)
- && settings->testAttribute(QWebEngineSettings::JavascriptCanPaste))
- std::move(callback).Run(blink::mojom::PermissionStatus::GRANTED);
- else
- std::move(callback).Run(blink::mojom::PermissionStatus::DENIED);
- return;
- } else if (!canRequestPermissionFor(permissionType)) {
- std::move(callback).Run(blink::mojom::PermissionStatus::DENIED);
- return;
- }
-
- int request_id = ++m_requestIdCount;
- auto requestOrigin = toQt(requesting_origin);
- m_requests.push_back({ request_id, permissionType, requestOrigin, std::move(callback) });
- contentsDelegate->requestFeaturePermission(permissionType, requestOrigin);
-}
-
-void PermissionManagerQt::RequestPermissions(const std::vector<blink::PermissionType> &permissions,
- content::RenderFrameHost *frameHost,
- const GURL &requesting_origin,
- bool /*user_gesture*/,
- base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus> &)> callback)
+void PermissionManagerQt::RequestPermissions(content::RenderFrameHost *frameHost,
+ const content::PermissionRequestDescription &requestDescription,
+ base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
{
- if (requesting_origin.is_empty()) {
- std::move(callback).Run(std::vector<blink::mojom::PermissionStatus>(permissions.size(), blink::mojom::PermissionStatus::DENIED));
+ if (requestDescription.requesting_origin.is_empty()) {
+ std::move(callback).Run(std::vector<content::PermissionStatus>(requestDescription.permissions.size(), blink::mojom::PermissionStatus::DENIED));
return;
}
@@ -214,23 +196,21 @@ void PermissionManagerQt::RequestPermissions(const std::vector<blink::Permission
Q_ASSERT(contentsDelegate);
bool answerable = true;
- std::vector<blink::mojom::PermissionStatus> result;
- result.reserve(permissions.size());
- for (blink::PermissionType permission : permissions) {
+ std::vector<content::PermissionStatus> result;
+ result.reserve(requestDescription.permissions.size());
+ for (blink::PermissionType permission : requestDescription.permissions) {
const ProfileAdapter::PermissionType permissionType = toQt(permission);
- if (permissionType == ProfileAdapter::UnsupportedPermission)
+ if (permissionType == ProfileAdapter::UnsupportedPermission) {
result.push_back(blink::mojom::PermissionStatus::DENIED);
- else if (permissionType == ProfileAdapter::ClipboardRead) {
- WebEngineSettings *settings = contentsDelegate->webEngineSettings();
- if (settings->testAttribute(QWebEngineSettings::JavascriptCanAccessClipboard)
- && settings->testAttribute(QWebEngineSettings::JavascriptCanPaste))
- result.push_back(blink::mojom::PermissionStatus::GRANTED);
- else
- result.push_back(blink::mojom::PermissionStatus::DENIED);
- } else {
+ continue;
+ }
+
+ auto status = getStatusFromSettings(permission, contentsDelegate->webEngineSettings());
+ if (status == blink::mojom::PermissionStatus::ASK) {
answerable = false;
break;
- }
+ } else
+ result.push_back(status);
}
if (answerable) {
std::move(callback).Run(result);
@@ -238,21 +218,21 @@ void PermissionManagerQt::RequestPermissions(const std::vector<blink::Permission
}
int request_id = ++m_requestIdCount;
- auto requestOrigin = toQt(requesting_origin);
- m_multiRequests.push_back({ request_id, permissions, requestOrigin, std::move(callback) });
- for (blink::PermissionType permission : permissions) {
+ auto requestOrigin = toQt(requestDescription.requesting_origin);
+ m_multiRequests.push_back({ request_id, requestDescription.permissions, requestOrigin, std::move(callback) });
+ for (blink::PermissionType permission : requestDescription.permissions) {
const ProfileAdapter::PermissionType permissionType = toQt(permission);
if (canRequestPermissionFor(permissionType))
contentsDelegate->requestFeaturePermission(permissionType, requestOrigin);
}
}
-void PermissionManagerQt::RequestPermissionsFromCurrentDocument(const std::vector<blink::PermissionType> &permissions,
- content::RenderFrameHost *frameHost,
- bool user_gesture,
+void PermissionManagerQt::RequestPermissionsFromCurrentDocument(content::RenderFrameHost *frameHost,
+ const content::PermissionRequestDescription &requestDescription,
base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback)
{
- RequestPermissions(permissions, frameHost, frameHost->GetLastCommittedOrigin().GetURL(), user_gesture, std::move(callback));
+
+ RequestPermissions(frameHost, requestDescription, std::move(callback));
}
blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatus(
@@ -280,14 +260,10 @@ blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForCurren
permission == blink::PermissionType::CLIPBOARD_SANITIZED_WRITE) {
WebContentsDelegateQt *delegate = static_cast<WebContentsDelegateQt *>(
content::WebContents::FromRenderFrameHost(render_frame_host)->GetDelegate());
- if (!delegate->webEngineSettings()->testAttribute(
- QWebEngineSettings::JavascriptCanAccessClipboard))
- return blink::mojom::PermissionStatus::DENIED;
- if (permission == blink::PermissionType::CLIPBOARD_READ_WRITE
- && !delegate->webEngineSettings()->testAttribute(
- QWebEngineSettings::JavascriptCanPaste))
- return blink::mojom::PermissionStatus::DENIED;
- return blink::mojom::PermissionStatus::GRANTED;
+ Q_ASSERT(delegate);
+ auto status = getStatusFromSettings(permission, delegate->webEngineSettings());
+ if (status != blink::mojom::PermissionStatus::ASK)
+ return status;
}
return GetPermissionStatus(
@@ -304,12 +280,22 @@ blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForWorker
return GetPermissionStatus(permission, url, url);
}
+blink::mojom::PermissionStatus PermissionManagerQt::GetPermissionStatusForEmbeddedRequester(
+ blink::PermissionType permission,
+ content::RenderFrameHost *render_frame_host,
+ const url::Origin &requesting_origin)
+{
+ return GetPermissionStatus(permission, requesting_origin.GetURL(),
+ render_frame_host->GetLastCommittedOrigin().GetURL());
+}
+
content::PermissionResult PermissionManagerQt::GetPermissionResultForOriginWithoutContext(
blink::PermissionType permission,
- const url::Origin &origin)
+ const url::Origin &requesting_origin,
+ const url::Origin &embedding_origin)
{
blink::mojom::PermissionStatus status =
- GetPermissionStatus(permission, origin.GetURL(), origin.GetURL());
+ GetPermissionStatus(permission, requesting_origin.GetURL(), embedding_origin.GetURL());
return content::PermissionResult(status, content::PermissionStatusSource::UNSPECIFIED);
}
diff --git a/src/core/permission_manager_qt.h b/src/core/permission_manager_qt.h
index 8778c538d..b91498d3d 100644
--- a/src/core/permission_manager_qt.h
+++ b/src/core/permission_manager_qt.h
@@ -4,7 +4,7 @@
#ifndef PERMISSION_MANAGER_QT_H
#define PERMISSION_MANAGER_QT_H
-#include "base/callback.h"
+#include "base/functional/callback.h"
#include "content/public/browser/permission_controller_delegate.h"
#include "profile_adapter.h"
@@ -23,13 +23,6 @@ public:
bool checkPermission(const QUrl &origin, ProfileAdapter::PermissionType type);
// content::PermissionManager implementation:
- void RequestPermission(
- blink::PermissionType permission,
- content::RenderFrameHost* render_frame_host,
- const GURL& requesting_origin,
- bool user_gesture,
- base::OnceCallback<void(blink::mojom::PermissionStatus)> callback) override;
-
blink::mojom::PermissionStatus GetPermissionStatus(
blink::PermissionType permission,
const GURL& requesting_origin,
@@ -39,7 +32,9 @@ public:
blink::mojom::PermissionStatus GetPermissionStatusForWorker(blink::PermissionType, content::RenderProcessHost *, const GURL &) override;
- content::PermissionResult GetPermissionResultForOriginWithoutContext(blink::PermissionType, const url::Origin &) override;
+ blink::mojom::PermissionStatus GetPermissionStatusForEmbeddedRequester(blink::PermissionType, content::RenderFrameHost*, const url::Origin&) override;
+
+ content::PermissionResult GetPermissionResultForOriginWithoutContext(blink::PermissionType, const url::Origin&, const url::Origin&) override;
void ResetPermission(
blink::PermissionType permission,
@@ -47,19 +42,14 @@ public:
const GURL& embedding_origin) override;
void RequestPermissions(
- const std::vector<blink::PermissionType>& permission,
- content::RenderFrameHost* render_frame_host,
- const GURL& requesting_origin,
- bool user_gesture,
- base::OnceCallback<void(
- const std::vector<blink::mojom::PermissionStatus>&)> callback) override;
+ content::RenderFrameHost *render_frame_host,
+ const content::PermissionRequestDescription &request_description,
+ base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus>&)> callback) override;
void RequestPermissionsFromCurrentDocument(
- const std::vector<blink::PermissionType>& permissions,
- content::RenderFrameHost* render_frame_host,
- bool user_gesture,
- base::OnceCallback<void(
- const std::vector<blink::mojom::PermissionStatus>&)> callback) override;
+ content::RenderFrameHost *render_frame_host,
+ const content::PermissionRequestDescription &request_description,
+ base::OnceCallback<void(const std::vector<blink::mojom::PermissionStatus> &)> callback) override;
content::PermissionControllerDelegate::SubscriptionId SubscribePermissionStatusChange(
blink::PermissionType permission,
diff --git a/src/core/pref_service_adapter.cpp b/src/core/pref_service_adapter.cpp
index 34251880e..544a84de1 100644
--- a/src/core/pref_service_adapter.cpp
+++ b/src/core/pref_service_adapter.cpp
@@ -26,6 +26,9 @@
#include "extensions/buildflags/buildflags.h"
#include "content/public/browser/browser_context.h"
+#include "components/pref_registry/pref_registry_syncable.h"
+#include "chrome/browser/devtools/devtools_settings.h"
+
#if QT_CONFIG(webengine_spellchecker)
#include "chrome/browser/spellchecker/spellcheck_service.h"
#include "components/spellcheck/browser/pref_names.h"
@@ -40,7 +43,7 @@
#endif
#if defined(Q_OS_WIN)
-#include "components/os_crypt/os_crypt.h"
+#include "components/os_crypt/sync/os_crypt.h"
#endif
namespace {
@@ -84,8 +87,6 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
registry->RegisterIntegerPref(prefs::kNotificationNextPersistentId, 10000);
registry->RegisterDictionaryPref(prefs::kPushMessagingAppIdentifierMap);
registry->RegisterListPref(prefs::kAccountInfo);
- registry->RegisterStringPref(prefs::kGoogleServicesLastAccountId,
- std::string());
registry->RegisterStringPref(prefs::kGoogleServicesLastUsername,
std::string());
registry->RegisterStringPref(prefs::kGoogleServicesAccountId, std::string());
@@ -110,6 +111,7 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
registry->RegisterListPref(extensions::pref_names::kNativeMessagingBlocklist);
registry->RegisterListPref(extensions::pref_names::kNativeMessagingAllowlist);
registry->RegisterBooleanPref(extensions::pref_names::kNativeMessagingUserLevelHosts, true);
+ registry->RegisterListPref(extensions::pref_names::kExtendedBackgroundLifetimeForPortConnectionsToUrls);
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
// Media device salt id key
@@ -121,11 +123,16 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
registry->RegisterBooleanPref(autofill::prefs::kAutofillProfileEnabled, false);
registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardEnabled, false);
registry->RegisterBooleanPref(autofill::prefs::kAutofillCreditCardFidoAuthEnabled, false);
- registry->RegisterBooleanPref(autofill::prefs::kAutofillWalletImportEnabled, false);
// devtools
registry->RegisterDictionaryPref(prefs::kDevToolsFileSystemPaths);
registry->RegisterDictionaryPref(prefs::kDevToolsEditedFiles);
+ registry->RegisterDictionaryPref(prefs::kDevToolsPreferences);
+ registry->RegisterBooleanPref(prefs::kDevToolsSyncPreferences, false);
+ // even if kDevToolsSyncPreferences is disabled, the js frontend tries to access
+ // these two. E.g.: 'clearPreferences', that is overridden by devtools_compatibility.js
+ registry->RegisterDictionaryPref(prefs::kDevToolsSyncedPreferencesSyncDisabled);
+ registry->RegisterDictionaryPref(prefs::kDevToolsSyncedPreferencesSyncEnabled);
registry->RegisterStringPref(prefs::kGoogleServicesSigninScopedDeviceId, std::string());
registry->RegisterStringPref(prefs::kGaiaCookieLastListAccountsData, std::string());
@@ -136,12 +143,6 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
m_prefService = factory.Create(registry);
}
- // Initialize salt value if none was stored before
- if (m_prefService->GetString(kPrefMediaDeviceIDSalt).empty()) {
- m_prefService->SetString(kPrefMediaDeviceIDSalt,
- content::BrowserContext::CreateRandomMediaDeviceIDSalt());
- }
-
#if QT_CONFIG(webengine_spellchecker)
// Ignore stored values for these options to preserve backwards compatibility.
m_prefService->ClearPref(spellcheck::prefs::kSpellCheckEnable);
diff --git a/src/core/printing/pdf_document_helper_client_qt.cpp b/src/core/printing/pdf_document_helper_client_qt.cpp
new file mode 100644
index 000000000..be1cc2e4c
--- /dev/null
+++ b/src/core/printing/pdf_document_helper_client_qt.cpp
@@ -0,0 +1,33 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+// based on chrome/browser/ui/pdf/chrome_pdf_document_helper_client.cc:
+
+#include "pdf_document_helper_client_qt.h"
+
+#include "content/public/browser/render_process_host.h"
+#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
+#include "extensions/common/constants.h"
+
+#include "pdf_util_qt.h"
+
+PDFDocumentHelperClientQt::PDFDocumentHelperClientQt() = default;
+PDFDocumentHelperClientQt::~PDFDocumentHelperClientQt() = default;
+
+content::RenderFrameHost *PDFDocumentHelperClientQt::FindPdfFrame(content::WebContents *contents)
+{
+ content::RenderFrameHost *main_frame = contents->GetPrimaryMainFrame();
+ content::RenderFrameHost *pdf_frame = QtWebEngineCore::FindPdfChildFrame(main_frame);
+ return pdf_frame ? pdf_frame : main_frame;
+}
+
+void PDFDocumentHelperClientQt::SetPluginCanSave(content::RenderFrameHost *render_frame_host, bool can_save)
+{
+ auto *guest_view = extensions::MimeHandlerViewGuest::FromRenderFrameHost(render_frame_host);
+ if (guest_view)
+ guest_view->SetPluginCanSave(can_save);
+}
+
+void PDFDocumentHelperClientQt::UpdateContentRestrictions(content::RenderFrameHost *, int)
+{
+}
diff --git a/src/core/printing/pdf_document_helper_client_qt.h b/src/core/printing/pdf_document_helper_client_qt.h
new file mode 100644
index 000000000..af58c7794
--- /dev/null
+++ b/src/core/printing/pdf_document_helper_client_qt.h
@@ -0,0 +1,27 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef PDF_DOCUMENT_HELPER_CLIENT_QT_H
+#define PDF_DOCUMENT_HELPER_CLIENT_QT_H
+
+#include "components/pdf/browser/pdf_document_helper_client.h"
+
+// based on chrome/browser/ui/pdf/chrome_pdf_document_helper_client.h:
+class PDFDocumentHelperClientQt : public pdf::PDFDocumentHelperClient // FIXME: rename
+{
+public:
+ PDFDocumentHelperClientQt();
+ PDFDocumentHelperClientQt(const PDFDocumentHelperClientQt&) = delete;
+ PDFDocumentHelperClientQt& operator=(const PDFDocumentHelperClientQt&) = delete;
+ ~PDFDocumentHelperClientQt() override;
+
+private:
+ // pdf::PDFDocumentHelperClient:
+ content::RenderFrameHost* FindPdfFrame(content::WebContents *contents) override;
+ void OnPDFHasUnsupportedFeature(content::WebContents *contents) override {}
+ void OnSaveURL(content::WebContents *contents) override {}
+ void SetPluginCanSave(content::RenderFrameHost *render_frame_host, bool can_save) override;
+ void UpdateContentRestrictions(content::RenderFrameHost *, int) override;
+};
+
+#endif // PDF_DOCUMENT_HELPER_CLIENT_QT_H
diff --git a/src/core/printing/pdf_stream_delegate_qt.cpp b/src/core/printing/pdf_stream_delegate_qt.cpp
index bb7b37532..8677c82bd 100644
--- a/src/core/printing/pdf_stream_delegate_qt.cpp
+++ b/src/core/printing/pdf_stream_delegate_qt.cpp
@@ -7,40 +7,44 @@
#include "base/no_destructor.h"
#include "chrome/grit/pdf_resources.h"
+#include "content/public/browser/document_user_data.h"
+#include "content/public/browser/navigation_handle.h"
#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
#include "extensions/common/constants.h"
#include "ui/base/resource/resource_bundle.h"
-// Associates a `pdf::PdfStreamDelegate::StreamInfo` with a `WebContents`.
-// `PdfStreamDelegateQt::MapToOriginalUrl()` initializes this in
-// `PdfNavigationThrottle`, and then `PdfStreamDelegateQt::GetStreamInfo()`
+// Associates a `pdf::PdfStreamDelegate::StreamInfo` with the PDF extension's
+// or Print Preview's `blink::Document`.
+// `ChromePdfStreamDelegate::MapToOriginalUrl()` initializes this in
+// `PdfNavigationThrottle`, and then `ChromePdfStreamDelegate::GetStreamInfo()`
// returns the stashed result to `PdfURLLoaderRequestInterceptor`.
-class StreamInfoHelper : public content::WebContentsUserData<StreamInfoHelper>
+class StreamInfoHelper : public content::DocumentUserData<StreamInfoHelper>
{
public:
absl::optional<pdf::PdfStreamDelegate::StreamInfo> TakeStreamInfo()
{ return std::move(stream_info_); }
private:
- friend class content::WebContentsUserData<StreamInfoHelper>;
- WEB_CONTENTS_USER_DATA_KEY_DECL();
+ friend class content::DocumentUserData<StreamInfoHelper>;
+ DOCUMENT_USER_DATA_KEY_DECL();
- StreamInfoHelper(content::WebContents *contents,
+ StreamInfoHelper(content::RenderFrameHost* embedder_frame,
pdf::PdfStreamDelegate::StreamInfo stream_info)
- : content::WebContentsUserData<StreamInfoHelper>(*contents),
+ : content::DocumentUserData<StreamInfoHelper>(embedder_frame),
stream_info_(std::move(stream_info)) {}
absl::optional<pdf::PdfStreamDelegate::StreamInfo> stream_info_;
};
-WEB_CONTENTS_USER_DATA_KEY_IMPL(StreamInfoHelper);
+DOCUMENT_USER_DATA_KEY_IMPL(StreamInfoHelper);
PdfStreamDelegateQt::PdfStreamDelegateQt() = default;
PdfStreamDelegateQt::~PdfStreamDelegateQt() = default;
-absl::optional<GURL> PdfStreamDelegateQt::MapToOriginalUrl(content::WebContents *contents, const GURL &stream_url)
+absl::optional<GURL> PdfStreamDelegateQt::MapToOriginalUrl(content::NavigationHandle &navigation_handle)
{
- StreamInfoHelper *helper = StreamInfoHelper::FromWebContents(contents);
+ content::RenderFrameHost *embedder_frame = navigation_handle.GetParentFrame();
+ StreamInfoHelper *helper = StreamInfoHelper::GetForCurrentDocument(embedder_frame);
if (helper) {
// PDF viewer and Print Preview only do this once per WebContents.
return absl::nullopt;
@@ -49,12 +53,13 @@ absl::optional<GURL> PdfStreamDelegateQt::MapToOriginalUrl(content::WebContents
GURL original_url;
StreamInfo info;
+ content::WebContents* contents = navigation_handle.GetWebContents();
extensions::MimeHandlerViewGuest *guest =
extensions::MimeHandlerViewGuest::FromWebContents(contents);
if (guest) {
base::WeakPtr<extensions::StreamContainer> stream = guest->GetStreamWeakPtr();
if (!stream || stream->extension_id() != extension_misc::kPdfExtensionId ||
- stream->stream_url() != stream_url ||
+ stream->stream_url() != navigation_handle.GetURL() ||
!stream->pdf_plugin_attributes()) {
return absl::nullopt;
}
@@ -71,17 +76,20 @@ absl::optional<GURL> PdfStreamDelegateQt::MapToOriginalUrl(content::WebContents
ui::ResourceBundle::GetSharedInstance().LoadDataResourceString(
IDR_PDF_PDF_INTERNAL_PLUGIN_WRAPPER_ROLLUP_JS));
- info.stream_url = stream_url;
+ info.stream_url = navigation_handle.GetURL();
info.original_url = original_url;
info.injected_script = injected_script.get();
- StreamInfoHelper::CreateForWebContents(contents, std::move(info));
+ StreamInfoHelper::CreateForCurrentDocument(embedder_frame, std::move(info));
return original_url;
}
absl::optional<pdf::PdfStreamDelegate::StreamInfo>
-PdfStreamDelegateQt::GetStreamInfo(content::WebContents *contents)
+PdfStreamDelegateQt::GetStreamInfo(content::RenderFrameHost* embedder_frame)
{
- StreamInfoHelper *helper = StreamInfoHelper::FromWebContents(contents);
+ if (!embedder_frame)
+ return absl::nullopt;
+
+ StreamInfoHelper *helper = StreamInfoHelper::GetForCurrentDocument(embedder_frame);
if (!helper)
return absl::nullopt;
diff --git a/src/core/printing/pdf_stream_delegate_qt.h b/src/core/printing/pdf_stream_delegate_qt.h
index 47621576f..fd279af72 100644
--- a/src/core/printing/pdf_stream_delegate_qt.h
+++ b/src/core/printing/pdf_stream_delegate_qt.h
@@ -16,8 +16,8 @@ public:
~PdfStreamDelegateQt() override;
// pdf::PdfStreamDelegate:
- absl::optional<GURL> MapToOriginalUrl(content::WebContents *contents, const GURL &stream_url) override;
- absl::optional<StreamInfo> GetStreamInfo(content::WebContents *contents) override;
+ absl::optional<GURL> MapToOriginalUrl(content::NavigationHandle &navigation_handle) override;
+ absl::optional<StreamInfo> GetStreamInfo(content::RenderFrameHost *embedder_frame) override;
};
#endif // PDF_STREAM_DELEGATE_QT_H
diff --git a/src/core/printing/pdf_web_contents_helper_client_qt.cpp b/src/core/printing/pdf_web_contents_helper_client_qt.cpp
deleted file mode 100644
index 4deb398c6..000000000
--- a/src/core/printing/pdf_web_contents_helper_client_qt.cpp
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-// based on chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc:
-
-#include "pdf_web_contents_helper_client_qt.h"
-
-#include "content/public/browser/render_process_host.h"
-#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h"
-#include "extensions/common/constants.h"
-
-namespace {
-bool IsPdfExtensionOrigin(const url::Origin &origin)
-{
- return origin.scheme() == extensions::kExtensionScheme &&
- origin.host() == extension_misc::kPdfExtensionId;
-}
-
-// from chrome/browser/pdf/pdf_frame_util.cc:
-content::RenderFrameHost *FindPdfChildFrame(content::RenderFrameHost *rfh)
-{
- if (!IsPdfExtensionOrigin(rfh->GetLastCommittedOrigin()))
- return nullptr;
-
- content::RenderFrameHost *pdf_rfh = nullptr;
- rfh->ForEachRenderFrameHost(
- [&pdf_rfh](content::RenderFrameHost *rfh) {
- if (!rfh->GetProcess()->IsPdf())
- return;
-
- DCHECK(IsPdfExtensionOrigin(rfh->GetParent()->GetLastCommittedOrigin()));
- DCHECK(!pdf_rfh);
- pdf_rfh = rfh;
- });
-
- return pdf_rfh;
-}
-} // namespace
-
-PDFWebContentsHelperClientQt::PDFWebContentsHelperClientQt() = default;
-PDFWebContentsHelperClientQt::~PDFWebContentsHelperClientQt() = default;
-
-content::RenderFrameHost *PDFWebContentsHelperClientQt::FindPdfFrame(content::WebContents *contents)
-{
- content::RenderFrameHost *main_frame = contents->GetPrimaryMainFrame();
- content::RenderFrameHost *pdf_frame = FindPdfChildFrame(main_frame);
- return pdf_frame ? pdf_frame : main_frame;
-}
-
-void PDFWebContentsHelperClientQt::SetPluginCanSave(content::RenderFrameHost *render_frame_host, bool can_save)
-{
- auto *guest_view = extensions::MimeHandlerViewGuest::FromRenderFrameHost(render_frame_host);
- if (guest_view)
- guest_view->SetPluginCanSave(can_save);
-}
-
-void PDFWebContentsHelperClientQt::UpdateContentRestrictions(content::RenderFrameHost *, int)
-{
-}
diff --git a/src/core/printing/pdf_web_contents_helper_client_qt.h b/src/core/printing/pdf_web_contents_helper_client_qt.h
deleted file mode 100644
index 10df8a746..000000000
--- a/src/core/printing/pdf_web_contents_helper_client_qt.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (C) 2022 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H
-#define PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H
-
-#include "components/pdf/browser/pdf_web_contents_helper_client.h"
-
-// based on chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h:
-class PDFWebContentsHelperClientQt : public pdf::PDFWebContentsHelperClient
-{
-public:
- PDFWebContentsHelperClientQt();
- PDFWebContentsHelperClientQt(const PDFWebContentsHelperClientQt&) = delete;
- PDFWebContentsHelperClientQt& operator=(const PDFWebContentsHelperClientQt&) = delete;
- ~PDFWebContentsHelperClientQt() override;
-
-private:
- // pdf::PDFWebContentsHelperClient:
- content::RenderFrameHost* FindPdfFrame(content::WebContents *contents) override;
- void OnPDFHasUnsupportedFeature(content::WebContents *contents) override {}
- void OnSaveURL(content::WebContents *contents) override {}
- void SetPluginCanSave(content::RenderFrameHost *render_frame_host, bool can_save) override;
- void UpdateContentRestrictions(content::RenderFrameHost *, int) override;
-};
-
-#endif // PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H
diff --git a/src/core/printing/pdfium_document_wrapper_qt.h b/src/core/printing/pdfium_document_wrapper_qt.h
index 727818a90..feb34e36a 100644
--- a/src/core/printing/pdfium_document_wrapper_qt.h
+++ b/src/core/printing/pdfium_document_wrapper_qt.h
@@ -21,7 +21,7 @@
namespace QtWebEngineCore {
-class Q_WEBENGINECORE_PRIVATE_EXPORT PdfiumDocumentWrapperQt
+class Q_WEBENGINECORE_EXPORT PdfiumDocumentWrapperQt
{
public:
PdfiumDocumentWrapperQt(const void *pdfData, size_t size, const char *password = nullptr);
diff --git a/src/core/printing/print_view_manager_base_qt.cpp b/src/core/printing/print_view_manager_base_qt.cpp
index f071b59ad..b2b8e34fc 100644
--- a/src/core/printing/print_view_manager_base_qt.cpp
+++ b/src/core/printing/print_view_manager_base_qt.cpp
@@ -65,30 +65,10 @@ void OnDidGetDefaultPrintSettings(scoped_refptr<printing::PrintQueriesQueue> que
// If user hasn't cancelled.
if (printer_query->cookie() && printer_query->settings().dpi()) {
queue->QueuePrinterQuery(std::move(printer_query));
- } else {
- printer_query->StopWorker();
}
}
}
-printing::mojom::PrintPagesParamsPtr CreateEmptyPrintPagesParamsPtr()
-{
- auto params = printing::mojom::PrintPagesParams::New();
- params->params = printing::mojom::PrintParams::New();
- return params;
-}
-
-// Runs |callback| with |params| to reply to
-// mojom::PrintManagerHost::UpdatePrintSettings.
-void UpdatePrintSettingsReply(printing::mojom::PrintManagerHost::UpdatePrintSettingsCallback callback,
- printing::mojom::PrintPagesParamsPtr params, bool canceled)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (!params)
- params = CreateEmptyPrintPagesParamsPtr();
- std::move(callback).Run(std::move(params), canceled);
-}
-
void OnDidUpdatePrintSettings(scoped_refptr<printing::PrintQueriesQueue> queue,
std::unique_ptr<printing::PrinterQuery> printer_query,
printing::mojom::PrintManagerHost::UpdatePrintSettingsCallback callback,
@@ -103,24 +83,21 @@ void OnDidUpdatePrintSettings(scoped_refptr<printing::PrintQueriesQueue> queue,
params->params->document_cookie = printer_query->cookie();
params->pages = printer_query->settings().ranges();
}
- bool canceled = printer_query->last_status() == printing::mojom::ResultCode::kCanceled;
- UpdatePrintSettingsReply(std::move(callback), std::move(params), canceled);
+ std::move(callback).Run(std::move(params));
if (printer_query->cookie() && printer_query->settings().dpi()) {
queue->QueuePrinterQuery(std::move(printer_query));
- } else {
- printer_query->StopWorker();
}
}
-
void OnDidScriptedPrint(scoped_refptr<printing::PrintQueriesQueue> queue,
std::unique_ptr<printing::PrinterQuery> printer_query,
printing::mojom::PrintManagerHost::ScriptedPrintCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- printing::mojom::PrintPagesParamsPtr params = CreateEmptyPrintPagesParamsPtr();
+ auto params = printing::mojom::PrintPagesParams::New();
+ params->params = printing::mojom::PrintParams::New();
if (printer_query->last_status() == printing::mojom::ResultCode::kSuccess && printer_query->settings().dpi()) {
RenderParamsFromPrintSettings(printer_query->settings(), params->params.get());
params->params->document_cookie = printer_query->cookie();
@@ -132,8 +109,6 @@ void OnDidScriptedPrint(scoped_refptr<printing::PrintQueriesQueue> queue,
if (has_dpi && has_valid_cookie) {
queue->QueuePrinterQuery(std::move(printer_query));
- } else {
- printer_query->StopWorker();
}
}
@@ -145,9 +120,6 @@ PrintViewManagerBaseQt::PrintViewManagerBaseQt(content::WebContents *contents)
, m_didPrintingSucceed(false)
, m_printerQueriesQueue(WebEngineContext::current()->getPrintJobManager()->queue())
{
- // FIXME: Check if this needs to be executed async:
- // TODO: Add isEnabled to profile
- PrintViewManagerBaseQt::UpdatePrintingEnabled();
}
PrintViewManagerBaseQt::~PrintViewManagerBaseQt()
@@ -181,18 +153,6 @@ void PrintViewManagerBaseQt::ScriptedPrintReply(ScriptedPrintCallback callback,
std::move(callback).Run(std::move(params));
}
-void PrintViewManagerBaseQt::UpdatePrintingEnabled()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- bool enabled = false;
-#if QT_CONFIG(webengine_printing_and_pdf)
- enabled = true;
-#endif
- web_contents()->ForEachRenderFrameHost([this, enabled](content::RenderFrameHost *rfh) {
- SendPrintingEnabled(enabled, rfh);
- });
-}
-
void PrintViewManagerBaseQt::NavigationStopped()
{
// Cancel the current job, wait for the worker to finish.
@@ -284,6 +244,7 @@ void PrintViewManagerBaseQt::GetDefaultPrintSettings(GetDefaultPrintSettingsCall
printer_query_ptr->GetDefaultSettings(
base::BindOnce(&OnDidGetDefaultPrintSettings, m_printerQueriesQueue,
std::move(printer_query), std::move(callback_wrapper)),
+ false,
!render_process_host->IsPdf());
}
@@ -298,6 +259,15 @@ void PrintViewManagerBaseQt::PrintingFailed(int32_t cookie, printing::mojom::Pri
ReleasePrinterQuery();
}
+void PrintViewManagerBaseQt::IsPrintingEnabled(IsPrintingEnabledCallback callback)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ bool enabled = false;
+#if QT_CONFIG(webengine_printing_and_pdf)
+ enabled = true;
+#endif
+ std::move(callback).Run(enabled);
+}
void PrintViewManagerBaseQt::ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr params,
printing::mojom::PrintManagerHost::ScriptedPrintCallback callback)
@@ -324,15 +294,6 @@ void PrintViewManagerBaseQt::ScriptedPrint(printing::mojom::ScriptedPrintParamsP
base::BindOnce(&OnDidScriptedPrint, m_printerQueriesQueue, std::move(printer_query), std::move(callback_wrapper)));
}
-void PrintViewManagerBaseQt::ShowInvalidPrinterSettingsError()
-{
-}
-
-void PrintViewManagerBaseQt::DidStartLoading()
-{
- UpdatePrintingEnabled();
-}
-
// Note: In PrintViewManagerQt we always initiate printing with
// printing::mojom::PrintRenderFrame::InitiatePrintPreview()
// so m_printingRFH is never set and used at the moment.
@@ -536,11 +497,10 @@ bool PrintViewManagerBaseQt::RunInnerMessageLoop()
m_quitInnerLoop = run_loop.QuitClosure();
- // Need to enable recursive task.
- {
- base::CurrentThread::ScopedNestableTaskAllower allow;
- run_loop.Run();
- }
+ auto weak_this = weak_ptr_factory_.GetWeakPtr();
+ run_loop.Run();
+ if (!weak_this)
+ return false;
bool success = !m_quitInnerLoop;
m_quitInnerLoop.Reset();
@@ -591,11 +551,8 @@ void PrintViewManagerBaseQt::ReleasePrinterQuery()
if (!printJobManager)
return;
- std::unique_ptr<printing::PrinterQuery> printerQuery;
- printerQuery = m_printerQueriesQueue->PopPrinterQuery(cookie);
- if (!printerQuery)
- return;
- printerQuery->StopWorker();
+ std::unique_ptr<printing::PrinterQuery> printerQuery =
+ m_printerQueriesQueue->PopPrinterQuery(cookie);
}
// Originally from print_preview_message_handler.cc:
@@ -605,32 +562,22 @@ void PrintViewManagerBaseQt::StopWorker(int documentCookie)
return;
std::unique_ptr<printing::PrinterQuery> printerQuery =
m_printerQueriesQueue->PopPrinterQuery(documentCookie);
- if (!printerQuery)
- return;
- printerQuery->StopWorker();
}
-void PrintViewManagerBaseQt::SendPrintingEnabled(bool enabled, content::RenderFrameHost* rfh)
-{
- if (rfh->IsRenderFrameLive())
- GetPrintRenderFrame(rfh)->SetPrintingEnabled(enabled);
-}
-
-void PrintViewManagerBaseQt::UpdatePrintSettings(int32_t cookie, base::Value::Dict job_settings,
+void PrintViewManagerBaseQt::UpdatePrintSettings(base::Value::Dict job_settings,
UpdatePrintSettingsCallback callback)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
if (!job_settings.FindInt(printing::kSettingPrinterType)) {
- UpdatePrintSettingsReply(std::move(callback), nullptr, false);
+ std::move(callback).Run(nullptr);
return;
}
content::RenderFrameHost *render_frame_host =
print_manager_host_receivers_.GetCurrentTargetFrame();
- std::unique_ptr<printing::PrinterQuery> printer_query = m_printerQueriesQueue->PopPrinterQuery(cookie);
- if (!printer_query)
- printer_query = m_printerQueriesQueue->CreatePrinterQuery(content::GlobalRenderFrameHostId());
+ std::unique_ptr<printing::PrinterQuery> printer_query =
+ m_printerQueriesQueue->CreatePrinterQuery(content::GlobalRenderFrameHostId());
auto *printer_query_ptr = printer_query.get();
printer_query_ptr->SetSettings(
diff --git a/src/core/printing/print_view_manager_base_qt.h b/src/core/printing/print_view_manager_base_qt.h
index 8201a4225..d4b5bfe82 100644
--- a/src/core/printing/print_view_manager_base_qt.h
+++ b/src/core/printing/print_view_manager_base_qt.h
@@ -36,9 +36,6 @@ class PrintViewManagerBaseQt : public printing::PrintManager
public:
~PrintViewManagerBaseQt() override;
- // Whether printing is enabled or not.
- void UpdatePrintingEnabled();
-
std::u16string RenderSourceName();
// mojom::PrintManagerHost:
@@ -46,11 +43,10 @@ public:
void DidPrintDocument(printing::mojom::DidPrintDocumentParamsPtr params,
DidPrintDocumentCallback callback) override;
void GetDefaultPrintSettings(GetDefaultPrintSettingsCallback callback) override;
- void UpdatePrintSettings(int32_t cookie, base::Value::Dict job_settings,
- UpdatePrintSettingsCallback callback) override;
+ void UpdatePrintSettings(base::Value::Dict, UpdatePrintSettingsCallback) override;
+ void IsPrintingEnabled(IsPrintingEnabledCallback callback) override;
void ScriptedPrint(printing::mojom::ScriptedPrintParamsPtr,
printing::mojom::PrintManagerHost::ScriptedPrintCallback) override;
- void ShowInvalidPrinterSettingsError() override;
void PrintingFailed(int32_t cookie,
printing::mojom::PrintFailureReason reason) override;
@@ -83,9 +79,6 @@ protected:
void StopWorker(int documentCookie);
private:
- // content::WebContentsObserver implementation.
- void DidStartLoading() override;
-
// Requests the RenderView to render all the missing pages for the print job.
// No-op if no print job is pending. Returns true if at least one page has
// been requested to the renderer.
@@ -136,9 +129,6 @@ private:
// Release the PrinterQuery associated with our |cookie_|.
void ReleasePrinterQuery();
- // Helper method for UpdatePrintingEnabled().
- void SendPrintingEnabled(bool enabled, content::RenderFrameHost* rfh);
-
private:
content::NotificationRegistrar m_registrar;
scoped_refptr<printing::PrintJob> m_printJob;
diff --git a/src/core/printing/print_view_manager_qt.cpp b/src/core/printing/print_view_manager_qt.cpp
index d8b6f1c1f..1d21c2fb9 100644
--- a/src/core/printing/print_view_manager_qt.cpp
+++ b/src/core/printing/print_view_manager_qt.cpp
@@ -8,6 +8,7 @@
#include "print_view_manager_qt.h"
+#include "pdf_util_qt.h"
#include "type_conversion.h"
#include "web_contents_adapter_client.h"
#include "web_contents_view_qt.h"
@@ -238,8 +239,12 @@ bool PrintViewManagerQt::PrintToPDFInternal(const QPageLayout &pageLayout,
if (web_contents()->IsCrashed())
return false;
- content::RenderFrameHost* rfh = web_contents()->GetPrimaryMainFrame();
- GetPrintRenderFrame(rfh)->InitiatePrintPreview(mojo::PendingAssociatedRemote<printing::mojom::PrintRenderer>(), false);
+ content::RenderFrameHost *rfh = web_contents()->GetPrimaryMainFrame();
+ // Use the plugin frame for printing if web_contents() is a PDF viewer guest
+ content::RenderFrameHost *full_page_plugin = GetFullPagePlugin(web_contents());
+ if (content::RenderFrameHost *pdf_rfh = FindPdfChildFrame(full_page_plugin ? full_page_plugin : rfh))
+ rfh = pdf_rfh;
+ GetPrintRenderFrame(rfh)->InitiatePrintPreview(false);
DCHECK(!m_printPreviewRfh);
m_printPreviewRfh = rfh;
@@ -277,7 +282,7 @@ void PrintViewManagerQt::resetPdfState()
void PrintViewManagerQt::PrintPreviewDone()
{
- if (IsPrintRenderFrameConnected(m_printPreviewRfh))
+ if (m_printPreviewRfh->IsRenderFrameLive() && IsPrintRenderFrameConnected(m_printPreviewRfh))
GetPrintRenderFrame(m_printPreviewRfh)->OnPrintPreviewDialogClosed();
m_printPreviewRfh = nullptr;
}
@@ -336,8 +341,23 @@ void PrintViewManagerQt::ShowScriptedPrintPreview(bool /*source_is_modifiable*/)
// ignore for now
}
-void PrintViewManagerQt::RequestPrintPreview(printing::mojom::RequestPrintPreviewParamsPtr /*params*/)
+void PrintViewManagerQt::RequestPrintPreview(printing::mojom::RequestPrintPreviewParamsPtr params)
{
+ if (!m_printPreviewRfh && params->webnode_only) {
+ // The preview was requested by the print button of PDF viewer plugin. The code path ends up here, because
+ // Chromium automatically initiated a preview generation. We don't want that, just notify our embedder
+ // like we do in SetupScriptedPrintPreview() after window.print() and let them decide what to do.
+ content::WebContentsView *view = static_cast<content::WebContentsImpl*>(web_contents()->GetOutermostWebContents())->GetView();
+ if (WebContentsAdapterClient *client = WebContentsViewQt::from(view)->client())
+ client->printRequested();
+ return;
+ }
+
+ if (m_printSettings.empty()) {
+ PrintPreviewDone();
+ return;
+ }
+
mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> printRenderFrame;
m_printPreviewRfh->GetRemoteAssociatedInterfaces()->GetInterface(&printRenderFrame);
printRenderFrame->PrintPreview(m_printSettings.Clone());
diff --git a/src/core/printing/printer_worker.cpp b/src/core/printing/printer_worker.cpp
index 9eb82c590..6032f2211 100644
--- a/src/core/printing/printer_worker.cpp
+++ b/src/core/printing/printer_worker.cpp
@@ -27,22 +27,8 @@ void PrinterWorker::print()
PdfiumDocumentWrapperQt pdfiumWrapper(m_data->constData(), m_data->size());
- const QPageRanges ranges = m_device->pageRanges();
- int toPage = ranges.firstPage();
- int fromPage = ranges.lastPage();
- bool ascendingOrder = true;
-
- if (fromPage == 0 && toPage == 0) {
- fromPage = 1;
- toPage = pdfiumWrapper.pageCount();
- }
- fromPage = qMax(1, fromPage);
- toPage = qMin(pdfiumWrapper.pageCount(), toPage);
-
- if (!m_firstPageFirst) {
- qSwap(fromPage, toPage);
- ascendingOrder = false;
- }
+ const int fromPage = m_firstPageFirst ? 0 : pdfiumWrapper.pageCount() - 1;
+ const int toPage = m_firstPageFirst ? pdfiumWrapper.pageCount() : -1;
int pageCopies = 1;
if (m_collateCopies) {
@@ -58,15 +44,13 @@ void PrinterWorker::print()
if (printedDocuments > 0)
m_device->newPage();
- int currentPageIndex = fromPage;
-
- for (int i = 0; true; i++) {
- QSizeF documentSize = (pdfiumWrapper.pageSize(currentPageIndex - 1) * resolution);
+ for (int i = fromPage; i != toPage; m_firstPageFirst ? i++ : i--) {
+ QSizeF documentSize = (pdfiumWrapper.pageSize(i) * resolution);
bool isLandscape = documentSize.width() > documentSize.height();
m_device->setPageOrientation(isLandscape ? QPageLayout::Landscape
: QPageLayout::Portrait);
- QRectF pageRect = m_device->pageLayout().pageSize().rectPixels(m_deviceResolution);
- documentSize = documentSize.scaled(pageRect.size(), Qt::KeepAspectRatio);
+ QRectF paintRect = m_device->pageLayout().paintRectPixels(m_deviceResolution);
+ documentSize = documentSize.scaled(paintRect.size(), Qt::KeepAspectRatio);
// setPageOrientation has to be called before qpainter.begin() or before
// qprinter.newPage() so correct metrics is used, therefore call begin now for only
@@ -77,29 +61,21 @@ void PrinterWorker::print()
return;
}
- if (i > 0)
+ if (i != fromPage)
m_device->newPage();
for (int printedPages = 0; printedPages < pageCopies; printedPages++) {
if (printedPages > 0)
m_device->newPage();
- QImage currentImage = pdfiumWrapper.pageAsQImage(
- currentPageIndex - 1, documentSize.width(), documentSize.height());
+ QImage currentImage =
+ pdfiumWrapper.pageAsQImage(i, documentSize.width(), documentSize.height());
if (currentImage.isNull()) {
Q_EMIT resultReady(false);
return;
}
painter.drawImage(0, 0, currentImage);
}
-
- if (currentPageIndex == toPage)
- break;
-
- if (ascendingOrder)
- currentPageIndex++;
- else
- currentPageIndex--;
}
}
painter.end();
diff --git a/src/core/printing/printer_worker.h b/src/core/printing/printer_worker.h
index b3ac07ad4..0d2454fa0 100644
--- a/src/core/printing/printer_worker.h
+++ b/src/core/printing/printer_worker.h
@@ -26,7 +26,7 @@ QT_END_NAMESPACE
namespace QtWebEngineCore {
-class Q_WEBENGINECORE_PRIVATE_EXPORT PrinterWorker : public QObject
+class Q_WEBENGINECORE_EXPORT PrinterWorker : public QObject
{
Q_OBJECT
public:
diff --git a/src/core/process_main.cpp b/src/core/process_main.cpp
index ce92db083..6a7d26ffd 100644
--- a/src/core/process_main.cpp
+++ b/src/core/process_main.cpp
@@ -39,7 +39,6 @@ int processMain(int argc, const char **argv)
CHECK(seatbelt.server->InitializeSandbox());
}
#endif // IS_MAC
-
return content::ContentMain(std::move(params));
}
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index e9e9aaeda..b26f9b1de 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -7,6 +7,7 @@
#include "base/task/cancelable_task_tracker.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time_to_iso8601.h"
+#include "components/embedder_support/user_agent_utils.h"
#include "components/favicon/core/favicon_service.h"
#include "components/history/content/browser/history_database_helper.h"
#include "components/history/core/browser/history_database_params.h"
@@ -39,6 +40,7 @@
#include <QCoreApplication>
#include <QDir>
+#include <QJsonObject>
#include <QSet>
#include <QString>
#include <QStandardPaths>
@@ -63,6 +65,7 @@ ProfileAdapter::ProfileAdapter(const QString &storageName):
, m_httpCacheType(DiskHttpCache)
, m_persistentCookiesPolicy(AllowPersistentCookies)
, m_visitedLinksPolicy(TrackVisitedLinksOnDisk)
+ , m_clientHintsEnabled(true)
, m_pushServiceEnabled(false)
, m_httpCacheMaxSize(0)
{
@@ -201,9 +204,9 @@ void ProfileAdapter::removeClient(ProfileAdapterClient *adapterClient)
m_clients.removeOne(adapterClient);
}
-void ProfileAdapter::cancelDownload(quint32 downloadId)
+bool ProfileAdapter::cancelDownload(quint32 downloadId)
{
- downloadManagerDelegate()->cancelDownload(downloadId);
+ return downloadManagerDelegate()->cancelDownload(downloadId);
}
void ProfileAdapter::pauseDownload(quint32 downloadId)
@@ -319,10 +322,13 @@ void ProfileAdapter::setHttpUserAgent(const QString &userAgent)
std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
for (content::WebContentsImpl *web_contents : list)
- if (web_contents->GetBrowserContext() == m_profile.data())
- web_contents->SetUserAgentOverride(blink::UserAgentOverride::UserAgentOnly(stdUserAgent), true);
+ if (web_contents->GetBrowserContext() == m_profile.data()) {
+ auto userAgentOverride = blink::UserAgentOverride::UserAgentOnly(stdUserAgent);
+ userAgentOverride.ua_metadata_override = m_profile->m_userAgentMetadata;
+ web_contents->SetUserAgentOverride(userAgentOverride, true);
+ }
- m_profile->ForEachStoragePartition(
+ m_profile->ForEachLoadedStoragePartition(
base::BindRepeating([](const std::string &user_agent, content::StoragePartition *storage_partition) {
storage_partition->GetNetworkContext()->SetUserAgent(user_agent);
}, stdUserAgent));
@@ -345,8 +351,6 @@ void ProfileAdapter::setHttpCacheType(ProfileAdapter::HttpCacheType newhttpCache
return;
if (!m_offTheRecord && !m_profile->m_profileIOData->isClearHttpCacheInProgress()) {
m_profile->m_profileIOData->resetNetworkContext();
- if (m_httpCacheType == NoCache)
- clearHttpCache();
}
}
@@ -464,7 +468,7 @@ const QList<QByteArray> ProfileAdapter::customUrlSchemes() const
void ProfileAdapter::updateCustomUrlSchemeHandlers()
{
- m_profile->ForEachStoragePartition(
+ m_profile->ForEachLoadedStoragePartition(
base::BindRepeating([](content::StoragePartition *storage_partition) {
storage_partition->ResetURLLoaderFactories();
}));
@@ -586,12 +590,116 @@ void ProfileAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage)
}
}
- m_profile->ForEachStoragePartition(
+ m_profile->ForEachLoadedStoragePartition(
base::BindRepeating([](std::string accept_language, content::StoragePartition *storage_partition) {
storage_partition->GetNetworkContext()->SetAcceptLanguage(accept_language);
}, http_accept_language));
}
+QVariant ProfileAdapter::clientHint(ClientHint clientHint) const
+{
+ blink::UserAgentMetadata &userAgentMetadata = m_profile->m_userAgentMetadata;
+ switch (clientHint) {
+ case ProfileAdapter::UAArchitecture:
+ return QVariant(toQString(userAgentMetadata.architecture));
+ case ProfileAdapter::UAPlatform:
+ return QVariant(toQString(userAgentMetadata.platform));
+ case ProfileAdapter::UAModel:
+ return QVariant(toQString(userAgentMetadata.model));
+ case ProfileAdapter::UAMobile:
+ return QVariant(userAgentMetadata.mobile);
+ case ProfileAdapter::UAFullVersion:
+ return QVariant(toQString(userAgentMetadata.full_version));
+ case ProfileAdapter::UAPlatformVersion:
+ return QVariant(toQString(userAgentMetadata.platform_version));
+ case ProfileAdapter::UABitness:
+ return QVariant(toQString(userAgentMetadata.bitness));
+ case ProfileAdapter::UAFullVersionList: {
+ QJsonObject ret;
+ for (const auto &value : userAgentMetadata.brand_full_version_list)
+ ret.insert(toQString(value.brand), QJsonValue(toQString(value.version)));
+ return QVariant(ret);
+ }
+ case ProfileAdapter::UAWOW64:
+ return QVariant(userAgentMetadata.wow64);
+ default:
+ return QVariant();
+ }
+}
+
+void ProfileAdapter::setClientHint(ClientHint clientHint, const QVariant &value)
+{
+ blink::UserAgentMetadata &userAgentMetadata = m_profile->m_userAgentMetadata;
+ switch (clientHint) {
+ case ProfileAdapter::UAArchitecture:
+ userAgentMetadata.architecture = value.toString().toStdString();
+ break;
+ case ProfileAdapter::UAPlatform:
+ userAgentMetadata.platform = value.toString().toStdString();
+ break;
+ case ProfileAdapter::UAModel:
+ userAgentMetadata.model = value.toString().toStdString();
+ break;
+ case ProfileAdapter::UAMobile:
+ userAgentMetadata.mobile = value.toBool();
+ break;
+ case ProfileAdapter::UAFullVersion:
+ userAgentMetadata.full_version = value.toString().toStdString();
+ break;
+ case ProfileAdapter::UAPlatformVersion:
+ userAgentMetadata.platform_version = value.toString().toStdString();
+ break;
+ case ProfileAdapter::UABitness:
+ userAgentMetadata.bitness = value.toString().toStdString();
+ break;
+ case ProfileAdapter::UAFullVersionList: {
+ userAgentMetadata.brand_full_version_list.clear();
+ QJsonObject fullVersionList = value.toJsonObject();
+ for (const QString &key : fullVersionList.keys())
+ userAgentMetadata.brand_full_version_list.push_back({
+ key.toStdString(),
+ fullVersionList.value(key).toString().toStdString()
+ });
+ break;
+ }
+ case ProfileAdapter::UAWOW64:
+ userAgentMetadata.wow64 = value.toBool();
+ break;
+ default:
+ break;
+ }
+
+ std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
+ for (content::WebContentsImpl *web_contents : list) {
+ if (web_contents->GetBrowserContext() == m_profile.data()) {
+ web_contents->GetMutableRendererPrefs()->user_agent_override.ua_metadata_override = userAgentMetadata;
+ web_contents->SyncRendererPrefs();
+ }
+ }
+}
+
+bool ProfileAdapter::clientHintsEnabled()
+{
+ return m_clientHintsEnabled;
+}
+
+void ProfileAdapter::setClientHintsEnabled(bool enabled)
+{
+ m_clientHintsEnabled = enabled;
+}
+
+void ProfileAdapter::resetClientHints()
+{
+ m_profile->m_userAgentMetadata = embedder_support::GetUserAgentMetadata();
+ std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
+ for (content::WebContentsImpl *web_contents : list) {
+ if (web_contents->GetBrowserContext() == m_profile.data()) {
+ web_contents->GetMutableRendererPrefs()->user_agent_override.ua_metadata_override = m_profile->m_userAgentMetadata;
+ web_contents->SyncRendererPrefs();
+ }
+ }
+}
+
void ProfileAdapter::clearHttpCache()
{
m_profile->m_profileIOData->clearHttpCache();
diff --git a/src/core/profile_adapter.h b/src/core/profile_adapter.h
index ab4622a4b..4be0ea51e 100644
--- a/src/core/profile_adapter.h
+++ b/src/core/profile_adapter.h
@@ -46,7 +46,7 @@ class UserResourceControllerHost;
class VisitedLinksManagerQt;
class WebContentsAdapterClient;
-class Q_WEBENGINECORE_PRIVATE_EXPORT ProfileAdapter : public QObject
+class Q_WEBENGINECORE_EXPORT ProfileAdapter : public QObject
{
public:
explicit ProfileAdapter(const QString &storagePrefix = QString());
@@ -68,7 +68,7 @@ public:
void addClient(ProfileAdapterClient *adapterClient);
void removeClient(ProfileAdapterClient *adapterClient);
- void cancelDownload(quint32 downloadId);
+ bool cancelDownload(quint32 downloadId);
void pauseDownload(quint32 downloadId);
void resumeDownload(quint32 downloadId);
void removeDownload(quint32 downloadId);
@@ -133,8 +133,8 @@ public:
NotificationPermission = 2,
AudioCapturePermission = 3,
VideoCapturePermission = 4,
- ClipboardRead = 5,
- ClipboardWrite = 6,
+ ClipboardReadWrite = 5,
+ LocalFontsPermission = 6,
};
enum PermissionState {
@@ -143,6 +143,18 @@ public:
DeniedPermission = 2
};
+ enum ClientHint : uchar {
+ UAArchitecture,
+ UAPlatform,
+ UAModel,
+ UAMobile,
+ UAFullVersion,
+ UAPlatformVersion,
+ UABitness,
+ UAFullVersionList,
+ UAWOW64,
+ };
+
HttpCacheType httpCacheType() const;
void setHttpCacheType(ProfileAdapter::HttpCacheType);
@@ -173,6 +185,12 @@ public:
QString httpAcceptLanguage() const;
void setHttpAcceptLanguage(const QString &httpAcceptLanguage);
+ QVariant clientHint(ClientHint clientHint) const;
+ void setClientHint(ClientHint clientHint, const QVariant &value);
+ bool clientHintsEnabled();
+ void setClientHintsEnabled(bool enabled);
+ void resetClientHints();
+
void clearHttpCache();
#if QT_CONFIG(ssl)
@@ -221,6 +239,7 @@ private:
QHash<QByteArray, QPointer<QWebEngineUrlSchemeHandler>> m_customUrlSchemeHandlers;
QHash<QByteArray, QWeakPointer<UserNotificationController>> m_ephemeralNotifications;
QHash<QByteArray, QSharedPointer<UserNotificationController>> m_persistentNotifications;
+ bool m_clientHintsEnabled;
QList<ProfileAdapterClient*> m_clients;
QList<WebContentsAdapterClient *> m_webContentsAdapterClients;
diff --git a/src/core/profile_adapter_client.h b/src/core/profile_adapter_client.h
index 846346b81..06ac0de8b 100644
--- a/src/core/profile_adapter_client.h
+++ b/src/core/profile_adapter_client.h
@@ -27,7 +27,7 @@ class WebContentsAdapterClient;
class WebEngineSettings;
class UserNotificationController;
-class Q_WEBENGINECORE_PRIVATE_EXPORT ProfileAdapterClient
+class Q_WEBENGINECORE_EXPORT ProfileAdapterClient
{
public:
// Keep in sync with content::DownloadItem::DownloadState
@@ -110,6 +110,8 @@ public:
virtual void addWebContentsAdapterClient(WebContentsAdapterClient *adapter) = 0;
virtual void removeWebContentsAdapterClient(WebContentsAdapterClient *adapter) = 0;
virtual WebEngineSettings *coreSettings() const = 0;
+ virtual void clearHttpCacheCompleted() = 0;
+
static QString downloadInterruptReasonToString(DownloadInterruptReason reason);
};
diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp
index c11d35c95..859aff8d4 100644
--- a/src/core/profile_io_data_qt.cpp
+++ b/src/core/profile_io_data_qt.cpp
@@ -4,29 +4,21 @@
#include "profile_io_data_qt.h"
#include "content/browser/storage_partition_impl.h"
-#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browsing_data_remover.h"
-#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/resource_context.h"
#include "content/public/browser/shared_cors_origin_access_list.h"
-#include "content/public/common/content_features.h"
-#include "net/ssl/ssl_config_service_defaults.h"
-#include "services/cert_verifier/cert_verifier_creation.h"
#include "services/cert_verifier/public/mojom/cert_verifier_service_factory.mojom.h"
#include "services/network/public/cpp/cors/origin_access_list.h"
-#include "services/network/public/mojom/cert_verifier_service.mojom.h"
#include "net/client_cert_qt.h"
#include "net/client_cert_store_data.h"
#include "net/cookie_monster_delegate_qt.h"
#include "net/system_network_context_manager.h"
+#include "profile_adapter_client.h"
#include "profile_qt.h"
#include "type_conversion.h"
-#include <QDebug>
-#include <mutex>
-
namespace QtWebEngineCore {
ProfileIODataQt::ProfileIODataQt(ProfileQt *profile)
@@ -65,11 +57,9 @@ void ProfileIODataQt::shutdownOnUIThread()
m_cookieDelegate->unsetMojoCookieManager();
m_proxyConfigMonitor.reset();
- if (m_clearHttpCacheInProgress) {
- m_clearHttpCacheInProgress = false;
- content::BrowsingDataRemover *remover =
- m_profileAdapter->profile()->GetBrowsingDataRemover();
- remover->RemoveObserver(&m_removerObserver);
+ if (m_clearHttpCacheState == Removing) {
+ m_clearHttpCacheState = Completed;
+ removeBrowsingDataRemoverObserver();
}
bool posted = content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE, this);
@@ -110,8 +100,8 @@ void ProfileIODataQt::initializeOnUIThread()
void ProfileIODataQt::clearHttpCache()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (!m_clearHttpCacheInProgress) {
- m_clearHttpCacheInProgress = true;
+ if (m_clearHttpCacheState == Completed) {
+ m_clearHttpCacheState = Removing;
content::BrowsingDataRemover *remover =
m_profileAdapter->profile()->GetBrowsingDataRemover();
remover->AddObserver(&m_removerObserver);
@@ -137,9 +127,9 @@ BrowsingDataRemoverObserverQt::BrowsingDataRemoverObserverQt(ProfileIODataQt *pr
void BrowsingDataRemoverObserverQt::OnBrowsingDataRemoverDone(uint64_t)
{
- Q_ASSERT(m_profileIOData->m_clearHttpCacheInProgress);
+ Q_ASSERT(m_profileIOData->m_clearHttpCacheState == ProfileIODataQt::Removing);
m_profileIOData->removeBrowsingDataRemoverObserver();
- m_profileIOData->m_clearHttpCacheInProgress = false;
+ m_profileIOData->m_clearHttpCacheState = ProfileIODataQt::Resetting;
m_profileIOData->resetNetworkContext();
}
@@ -160,13 +150,44 @@ void ProfileIODataQt::setFullConfiguration()
void ProfileIODataQt::resetNetworkContext()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ Q_ASSERT(m_clearHttpCacheState != Removing);
setFullConfiguration();
- m_profile->ForEachStoragePartition(
- base::BindRepeating([](content::StoragePartition *storage) {
+ m_profile->ForEachLoadedStoragePartition(
+ base::BindRepeating([](ProfileIODataQt *profileData,
+ content::StoragePartition *storage) {
+ storage->SetNetworkContextCreatedObserver(profileData);
+
auto storage_impl = static_cast<content::StoragePartitionImpl *>(storage);
storage_impl->ResetURLLoaderFactories();
storage_impl->ResetNetworkContext();
- }));
+ }, this));
+}
+
+void ProfileIODataQt::OnNetworkContextCreated(content::StoragePartition *storage)
+{
+ Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+
+ storage->SetNetworkContextCreatedObserver(nullptr);
+
+ if (m_clearHttpCacheState != Resetting)
+ return;
+
+ bool pendingReset = false;
+ m_profile->ForEachLoadedStoragePartition(
+ base::BindRepeating([](bool *pendingReset,
+ ProfileIODataQt *profileData,
+ content::StoragePartition *storage) {
+ if (storage->GetNetworkContextCreatedObserver() == profileData)
+ *pendingReset = true;
+ }, &pendingReset, this));
+
+ if (pendingReset)
+ return;
+
+ m_clearHttpCacheState = Completed;
+
+ for (ProfileAdapterClient *client : m_profileAdapter->clients())
+ client->clearHttpCacheCompleted();
}
bool ProfileIODataQt::canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) const
@@ -208,8 +229,6 @@ void ProfileIODataQt::ConfigureNetworkContextParams(bool in_memory,
network_context_params->http_cache_enabled = m_httpCacheType != ProfileAdapter::NoCache;
network_context_params->http_cache_max_size = m_httpCacheMaxSize;
- if (m_httpCacheType == ProfileAdapter::DiskHttpCache && !m_httpCachePath.isEmpty() && !m_inMemoryOnly && !in_memory)
- network_context_params->http_cache_directory = toFilePath(m_httpCachePath);
network_context_params->persist_session_cookies = false;
if (!m_inMemoryOnly && !in_memory) {
@@ -219,6 +238,8 @@ void ProfileIODataQt::ConfigureNetworkContextParams(bool in_memory,
network_context_params->file_paths->http_server_properties_file_name = base::FilePath::FromASCII("Network Persistent State");
network_context_params->file_paths->transport_security_persister_file_name = base::FilePath::FromASCII("TransportSecurity");
network_context_params->file_paths->trust_token_database_name = base::FilePath::FromASCII("Trust Tokens");
+ if (m_httpCacheType == ProfileAdapter::DiskHttpCache && !m_httpCachePath.isEmpty())
+ network_context_params->file_paths->http_cache_directory = toFilePath(m_httpCachePath);
if (m_persistentCookiesPolicy != ProfileAdapter::NoPersistentCookies) {
network_context_params->file_paths->cookie_database_name = base::FilePath::FromASCII("Cookies");
network_context_params->restore_old_session_cookies = m_persistentCookiesPolicy == ProfileAdapter::ForcePersistentCookies;
diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h
index 430efedb4..0d032e4dc 100644
--- a/src/core/profile_io_data_qt.h
+++ b/src/core/profile_io_data_qt.h
@@ -5,7 +5,7 @@
#define PROFILE_IO_DATA_QT_H
#include "content/public/browser/browsing_data_remover.h"
-#include "chrome/browser/profiles/profile.h"
+#include "content/public/browser/storage_partition.h"
#include "extensions/buildflags/buildflags.h"
#include "net/proxy_config_monitor.h"
@@ -13,21 +13,25 @@
#include <QtCore/QString>
#include <QtCore/QPointer>
-#include <QtCore/QMutex>
+#include <QtCore/QRecursiveMutex>
namespace cert_verifier {
namespace mojom {
class CertVerifierCreationParams;
}}
-namespace net {
-class ClientCertStore;
+namespace content {
+class ResourceContext;
}
namespace extensions {
class ExtensionSystemQt;
}
+namespace net {
+class ClientCertStore;
+}
+
namespace QtWebEngineCore {
struct ClientCertificateStoreData;
@@ -49,9 +53,15 @@ private:
// we still use shared memebers and use mutex which breaks
// idea for this object, but this is wip.
-class ProfileIODataQt {
+class ProfileIODataQt : public content::StoragePartition::NetworkContextCreatedObserver {
public:
+ enum ClearHttpCacheState {
+ Completed = 0,
+ Removing,
+ Resetting
+ };
+
ProfileIODataQt(ProfileQt *profile); // runs on ui thread
virtual ~ProfileIODataQt();
@@ -68,8 +78,9 @@ public:
void setFullConfiguration(); // runs on ui thread
void resetNetworkContext(); // runs on ui thread
+
void clearHttpCache(); // runs on ui thread
- bool isClearHttpCacheInProgress() { return m_clearHttpCacheInProgress; }
+ bool isClearHttpCacheInProgress() const { return m_clearHttpCacheState != Completed; }
void ConfigureNetworkContextParams(bool in_memory,
const base::FilePath &relative_partition_path,
@@ -86,6 +97,9 @@ public:
CookieMonsterDelegateQt *cookieDelegate() const { return m_cookieDelegate.get(); }
+ // content::StoragePartition::NetworkContextCreatedObserver overrides:
+ void OnNetworkContextCreated(content::StoragePartition *storage) override; // runs on ui thread
+
private:
void removeBrowsingDataRemoverObserver();
@@ -109,7 +123,7 @@ private:
int m_httpCacheMaxSize = 0;
BrowsingDataRemoverObserverQt m_removerObserver;
QString m_dataPath;
- bool m_clearHttpCacheInProgress = false;
+ ClearHttpCacheState m_clearHttpCacheState = Completed;
base::WeakPtrFactory<ProfileIODataQt> m_weakPtrFactory; // this should be always the last member
friend class BrowsingDataRemoverObserverQt;
diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp
index 410340fb8..293e8d557 100644
--- a/src/core/profile_qt.cpp
+++ b/src/core/profile_qt.cpp
@@ -10,59 +10,41 @@
#include "file_system_access/file_system_access_permission_context_factory_qt.h"
#include "net/ssl_host_state_delegate_qt.h"
#include "permission_manager_qt.h"
+#include "profile_io_data_qt.h"
#include "platform_notification_service_qt.h"
#include "qtwebenginecoreglobal_p.h"
#include "type_conversion.h"
#include "web_engine_library_info.h"
#include "web_engine_context.h"
-#include "base/barrier_closure.h"
-#include "base/time/time.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/cors_origin_pattern_setter.h"
-#include "content/public/browser/shared_cors_origin_access_list.h"
-#include "content/public/browser/storage_partition.h"
-
#include "base/base_paths.h"
#include "base/files/file_util.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "components/prefs/pref_member.h"
#include "components/prefs/pref_service.h"
-#include "components/prefs/in_memory_pref_store.h"
-#include "components/prefs/json_pref_store.h"
-#include "components/prefs/pref_service.h"
-#include "components/prefs/pref_service_factory.h"
-#include "components/prefs/pref_registry_simple.h"
#include "components/user_prefs/user_prefs.h"
#include "components/profile_metrics/browser_profile_type.h"
-#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "content/public/browser/browser_thread.h"
#include "chrome/browser/push_messaging/push_messaging_app_identifier.h"
#include "chrome/browser/push_messaging/push_messaging_service_factory.h"
#include "chrome/browser/push_messaging/push_messaging_service_impl.h"
-#include "chrome/common/pref_names.h"
-#if QT_CONFIG(webengine_spellchecker)
-#include "chrome/browser/spellchecker/spellcheck_service.h"
-#include "components/spellcheck/browser/pref_names.h"
-#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
+#include "base/command_line.h"
#include "components/guest_view/browser/guest_view_manager.h"
-#include "extensions/browser/pref_names.h"
-#include "extensions/browser/process_manager.h"
-#include "extensions/common/constants.h"
+#include "extensions/browser/extension_pref_value_map_factory.h"
+#include "extensions/browser/extension_prefs.h"
+#include "extensions/browser/extension_prefs_factory.h"
+#include "extensions/browser/extensions_browser_client.h"
#include "extensions/extension_system_qt.h"
#endif
-#if defined(Q_OS_WIN)
-#include "components/os_crypt/os_crypt.h"
-#endif
-
namespace QtWebEngineCore {
ProfileQt::ProfileQt(ProfileAdapter *profileAdapter)
: m_profileIOData(new ProfileIODataQt(this))
, m_profileAdapter(profileAdapter)
+ , m_userAgentMetadata(embedder_support::GetUserAgentMetadata())
#if BUILDFLAG(ENABLE_EXTENSIONS)
, m_extensionSystem(nullptr)
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
@@ -246,6 +228,7 @@ content::FileSystemAccessPermissionContext *ProfileQt::GetFileSystemAccessPermis
void ProfileQt::setupPrefService()
{
+ const bool recreation = m_prefServiceAdapter.prefService() != nullptr;
profile_metrics::SetBrowserProfileType(this,
IsOffTheRecord()
? profile_metrics::BrowserProfileType::kIncognito
@@ -253,12 +236,28 @@ void ProfileQt::setupPrefService()
// Remove previous handler before we set a new one or we will assert
// TODO: Remove in Qt6
- if (m_prefServiceAdapter.prefService() != nullptr) {
+ if (recreation) {
user_prefs::UserPrefs::Remove(this);
m_prefServiceAdapter.commit();
}
m_prefServiceAdapter.setup(*m_profileAdapter);
user_prefs::UserPrefs::Set(this, m_prefServiceAdapter.prefService());
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ if (recreation) {
+ // Recreate ExtensionPrefs to update its pointer to the new PrefService
+ extensions::ExtensionsBrowserClient *client = extensions::ExtensionsBrowserClient::Get();
+ std::vector<extensions::EarlyExtensionPrefsObserver *> prefsObservers;
+ client->GetEarlyExtensionPrefsObservers(this, &prefsObservers);
+ auto extensionPrefs = extensions::ExtensionPrefs::Create(
+ this, client->GetPrefServiceForContext(this),
+ this->GetPath().AppendASCII(extensions::kInstallDirectoryName),
+ ExtensionPrefValueMapFactory::GetForBrowserContext(this),
+ client->AreExtensionsDisabled(*base::CommandLine::ForCurrentProcess(), this),
+ prefsObservers);
+ extensions::ExtensionPrefsFactory::GetInstance()->SetInstanceForTesting(this, std::move(extensionPrefs));
+ }
+#endif
}
PrefServiceAdapter &ProfileQt::prefServiceAdapter()
@@ -271,6 +270,11 @@ const PrefServiceAdapter &ProfileQt::prefServiceAdapter() const
return m_prefServiceAdapter;
}
+const blink::UserAgentMetadata &ProfileQt::userAgentMetadata()
+{
+ return m_userAgentMetadata;
+}
+
content::PlatformNotificationService *ProfileQt::GetPlatformNotificationService()
{
if (!m_platformNotificationService)
diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h
index 9fb8cb444..b5cd08db1 100644
--- a/src/core/profile_qt.h
+++ b/src/core/profile_qt.h
@@ -5,16 +5,16 @@
#define PROFILE_QT_H
#include "chrome/browser/profiles/profile.h"
-#include "content/public/browser/content_browser_client.h"
-#include "content/public/browser/resource_context.h"
+#include "components/embedder_support/user_agent_utils.h"
#include "extensions/buildflags/buildflags.h"
#include "pref_service_adapter.h"
-#include "profile_io_data_qt.h"
-#include <QtGlobal>
-class InMemoryPrefStore;
class PrefService;
+namespace content {
+class ResourceContext;
+}
+
namespace extensions {
class ExtensionSystemQt;
}
@@ -22,8 +22,9 @@ class ExtensionSystemQt;
namespace QtWebEngineCore {
class BrowsingDataRemoverDelegateQt;
-class ProfileAdapter;
class PermissionManagerQt;
+class ProfileAdapter;
+class ProfileIODataQt;
class SSLHostStateDelegateQt;
class ProfileQt : public Profile
@@ -54,7 +55,6 @@ public:
content::ClientHintsControllerDelegate *GetClientHintsControllerDelegate() override;
content::StorageNotificationService *GetStorageNotificationService() override;
content::PlatformNotificationService *GetPlatformNotificationService() override;
- std::string GetMediaDeviceIDSalt() override;
content::FileSystemAccessPermissionContext *GetFileSystemAccessPermissionContext() override;
content::ReduceAcceptLanguageControllerDelegate *GetReduceAcceptLanguageControllerDelegate() override;
@@ -65,6 +65,7 @@ public:
void DoFinalInit();
ProfileAdapter *profileAdapter() { return m_profileAdapter; }
+ std::string GetMediaDeviceIDSalt();
#if QT_CONFIG(webengine_spellchecker)
void FailedToLoadDictionary(const std::string &language) override;
@@ -78,9 +79,10 @@ public:
void setupPrefService();
PrefServiceAdapter &prefServiceAdapter();
-
const PrefServiceAdapter &prefServiceAdapter() const;
+ const blink::UserAgentMetadata &userAgentMetadata();
+
private:
std::unique_ptr<BrowsingDataRemoverDelegateQt> m_removerDelegate;
std::unique_ptr<PermissionManagerQt> m_permissionManager;
@@ -89,6 +91,7 @@ private:
std::unique_ptr<content::PlatformNotificationService> m_platformNotificationService;
ProfileAdapter *m_profileAdapter;
PrefServiceAdapter m_prefServiceAdapter;
+ blink::UserAgentMetadata m_userAgentMetadata;
#if BUILDFLAG(ENABLE_EXTENSIONS)
extensions::ExtensionSystemQt *m_extensionSystem;
diff --git a/src/core/render_view_context_menu_qt.h b/src/core/render_view_context_menu_qt.h
index b7f6744cd..1188f6cd4 100644
--- a/src/core/render_view_context_menu_qt.h
+++ b/src/core/render_view_context_menu_qt.h
@@ -15,13 +15,13 @@
#ifndef RENDER_VIEW_CONTEXT_MENU_QT_H
#define RENDER_VIEW_CONTEXT_MENU_QT_H
-#include "web_contents_adapter_client.h"
+#include "qtwebenginecoreglobal.h"
QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest)
namespace QtWebEngineCore {
-class Q_WEBENGINECORE_PRIVATE_EXPORT RenderViewContextMenuQt
+class Q_WEBENGINECORE_EXPORT RenderViewContextMenuQt
{
public:
enum ContextMenuItem {
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 3d4e5bbc2..888043fda 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -12,7 +12,6 @@
#include "web_contents_adapter_client.h"
#include "web_event_factory.h"
-#include "base/threading/thread_task_runner_handle.h"
#include "components/viz/common/features.h"
#include "components/viz/common/frame_sinks/begin_frame_source.h"
#include "components/viz/common/surfaces/frame_sink_id_allocator.h"
@@ -47,7 +46,7 @@
#endif
#if defined(USE_AURA)
-#include "ui/wm/core/cursors_aura.h"
+#include "ui/wm/core/cursor_util.h"
#include "ui/base/cursor/cursor_size.h"
#endif
@@ -145,7 +144,7 @@ public:
RenderWidgetHostViewQt::RenderWidgetHostViewQt(content::RenderWidgetHost *widget)
: content::RenderWidgetHostViewBase::RenderWidgetHostViewBase(widget)
- , m_taskRunner(base::ThreadTaskRunnerHandle::Get())
+ , m_taskRunner(base::SingleThreadTaskRunner::GetCurrentDefault())
, m_gestureProvider(QtGestureProviderConfig(), this)
, m_frameSinkId(host()->GetFrameSinkId())
, m_delegateClient(new RenderWidgetHostViewQtDelegateClient(this))
@@ -368,6 +367,9 @@ gfx::Rect RenderWidgetHostViewQt::GetViewBounds()
void RenderWidgetHostViewQt::UpdateBackgroundColor()
{
+ if (!m_delegate)
+ return;
+
DCHECK(GetBackgroundColor());
SkColor color = *GetBackgroundColor();
@@ -478,14 +480,13 @@ bool RenderWidgetHostViewQt::updateCursorFromResource(ui::mojom::CursorType type
return true;
}
-void RenderWidgetHostViewQt::UpdateCursor(const content::WebCursor &webCursor)
+void RenderWidgetHostViewQt::UpdateCursor(const ui::Cursor &webCursor)
{
DisplayCursor(webCursor);
}
-void RenderWidgetHostViewQt::DisplayCursor(const content::WebCursor &webCursor)
+void RenderWidgetHostViewQt::DisplayCursor(const ui::Cursor &cursorInfo)
{
- const ui::Cursor &cursorInfo = webCursor.cursor();
Qt::CursorShape shape = Qt::ArrowCursor;
switch (cursorInfo.type()) {
case ui::mojom::CursorType::kNull:
@@ -614,7 +615,9 @@ void RenderWidgetHostViewQt::ImeCancelComposition()
qApp->inputMethod()->reset();
}
-void RenderWidgetHostViewQt::ImeCompositionRangeChanged(const gfx::Range&, const std::vector<gfx::Rect>&)
+void RenderWidgetHostViewQt::ImeCompositionRangeChanged(const gfx::Range &,
+ const absl::optional<std::vector<gfx::Rect>> &,
+ const absl::optional<std::vector<gfx::Rect>> &)
{
// FIXME: not implemented?
QT_NOT_YET_IMPLEMENTED
@@ -682,9 +685,11 @@ void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputMana
// In case of text selection, the update is expected in RenderWidgetHostViewQt::selectionChanged().
if (GetSelectedText().empty()) {
- // At this point it is unknown whether the text input state has been updated due to a text selection.
- // Keep the cursor position updated for cursor movements too.
- delegateClient()->setCursorPosition(state->selection.start());
+ if (state->composition.has_value()) {
+ delegateClient()->setCursorPosition(state->composition->start());
+ } else {
+ delegateClient()->setCursorPosition(state->selection.start());
+ }
m_delegate->inputMethodStateChanged(type != ui::TEXT_INPUT_TYPE_NONE, type == ui::TEXT_INPUT_TYPE_PASSWORD);
}
@@ -831,11 +836,11 @@ void RenderWidgetHostViewQt::notifyHidden()
m_delegatedFrameHost->DetachFromCompositor();
}
-void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, blink::mojom::InputEventResultState ack_result) {
- Q_UNUSED(touch);
- const bool eventConsumed = ack_result == blink::mojom::InputEventResultState::kConsumed;
- const bool isSetNonBlocking = content::InputEventResultStateIsSetNonBlocking(ack_result);
- m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, isSetNonBlocking);
+void RenderWidgetHostViewQt::ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, blink::mojom::InputEventResultState ack_result)
+{
+ const bool eventConsumed = (ack_result == blink::mojom::InputEventResultState::kConsumed);
+ const bool isSetBlocking = content::InputEventResultStateIsSetBlocking(ack_result);
+ m_gestureProvider.OnTouchEventAck(touch.event.unique_touch_event_id, eventConsumed, isSetBlocking);
}
void RenderWidgetHostViewQt::processMotionEvent(const ui::MotionEvent &motionEvent)
@@ -979,7 +984,6 @@ void RenderWidgetHostViewQt::TakeFallbackContentFrom(content::RenderWidgetHostVi
CopyBackgroundColorIfPresentFrom(*viewQt);
m_delegatedFrameHost->TakeFallbackContentFrom(viewQt->m_delegatedFrameHost.get());
- host()->GetContentRenderingTimeoutFrom(viewQt->host());
}
void RenderWidgetHostViewQt::EnsureSurfaceSynchronizedForWebTest()
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index 25fd20115..a55e04dd8 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -77,12 +77,14 @@ public:
blink::mojom::PointerLockResult LockMouse(bool) override;
blink::mojom::PointerLockResult ChangeMouseLock(bool) override;
void UnlockMouse() override;
- void UpdateCursor(const content::WebCursor&) override;
- void DisplayCursor(const content::WebCursor&) override;
+ void UpdateCursor(const ui::Cursor&) override;
+ void DisplayCursor(const ui::Cursor&) override;
content::CursorManager *GetCursorManager() override;
void SetIsLoading(bool) override;
void ImeCancelComposition() override;
- void ImeCompositionRangeChanged(const gfx::Range&, const std::vector<gfx::Rect>&) override;
+ void ImeCompositionRangeChanged(const gfx::Range &,
+ const absl::optional<std::vector<gfx::Rect>> &,
+ const absl::optional<std::vector<gfx::Rect>> &) override;
void RenderProcessGone() override;
bool TransformPointToCoordSpaceForView(const gfx::PointF &point,
content::RenderWidgetHostViewBase *target_view,
@@ -132,9 +134,9 @@ public:
void SetWindowFrameInScreen(const gfx::Rect&) override { QT_NOT_YET_IMPLEMENTED }
#endif // BUILDFLAG(IS_MAC)
void NotifyHostAndDelegateOnWasShown(blink::mojom::RecordContentToVisibleTimeRequestPtr) override { QT_NOT_YET_IMPLEMENTED }
- void RequestPresentationTimeFromHostOrDelegate(blink::mojom::RecordContentToVisibleTimeRequestPtr) override { QT_NOT_YET_IMPLEMENTED }
- void CancelPresentationTimeRequestForHostAndDelegate() override { QT_NOT_YET_IMPLEMENTED }
-
+ void RequestSuccessfulPresentationTimeFromHostOrDelegate(blink::mojom::RecordContentToVisibleTimeRequestPtr) override {}
+ void CancelSuccessfulPresentationTimeRequestForHostAndDelegate() override {}
+ void InvalidateLocalSurfaceIdAndAllocationGroup() override {}
// Overridden from ui::GestureProviderClient.
void OnGestureEvent(const ui::GestureEventData& gesture) override;
diff --git a/src/core/render_widget_host_view_qt_delegate.h b/src/core/render_widget_host_view_qt_delegate.h
index 649fda77b..b1f33db7a 100644
--- a/src/core/render_widget_host_view_qt_delegate.h
+++ b/src/core/render_widget_host_view_qt_delegate.h
@@ -29,7 +29,7 @@ QT_END_NAMESPACE
namespace QtWebEngineCore {
class WebContentsAdapterClient;
-class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegate {
+class Q_WEBENGINECORE_EXPORT RenderWidgetHostViewQtDelegate {
public:
virtual ~RenderWidgetHostViewQtDelegate() { }
virtual void initAsPopup(const QRect&) = 0;
diff --git a/src/core/render_widget_host_view_qt_delegate_client.cpp b/src/core/render_widget_host_view_qt_delegate_client.cpp
index 1b30e9953..3e8cad669 100644
--- a/src/core/render_widget_host_view_qt_delegate_client.cpp
+++ b/src/core/render_widget_host_view_qt_delegate_client.cpp
@@ -16,9 +16,7 @@
#include <QEvent>
#include <QInputMethodEvent>
-#include <QScopeGuard>
#include <QSet>
-#include <QSGNode>
#include <QStyleHints>
#include <QTextFormat>
#include <QVariant>
@@ -346,6 +344,7 @@ QVariant RenderWidgetHostViewQtDelegateClient::inputMethodQuery(Qt::InputMethodQ
}
return QVariant();
}
+ case Qt::ImAbsolutePosition:
case Qt::ImCursorPosition:
return m_cursorPosition;
case Qt::ImAnchorPosition:
@@ -493,14 +492,14 @@ void RenderWidgetHostViewQtDelegateClient::handleKeyEvent(QKeyEvent *event)
bool keyDownTextInsertion =
webEvent.GetType() == blink::WebInputEvent::Type::kRawKeyDown && webEvent.text[0];
- webEvent.skip_in_browser = keyDownTextInsertion;
+ webEvent.skip_if_unhandled = keyDownTextInsertion;
m_rwhv->GetFocusedWidget()->ForwardKeyboardEvent(webEvent);
if (keyDownTextInsertion) {
// Blink won't consume the RawKeyDown, but rather the Char event in this case.
// The RawKeyDown is skipped on the way back (see above).
// The same os_event will be set on both NativeWebKeyboardEvents.
- webEvent.skip_in_browser = false;
+ webEvent.skip_if_unhandled = false;
webEvent.SetType(blink::WebInputEvent::Type::kChar);
m_rwhv->GetFocusedWidget()->ForwardKeyboardEvent(webEvent);
}
@@ -528,7 +527,7 @@ void RenderWidgetHostViewQtDelegateClient::handleTouchEvent(QTouchEvent *event)
m_eventsToNowDelta = (base::TimeTicks::Now() - eventTimestamp).InMicroseconds();
eventTimestamp += base::Microseconds(m_eventsToNowDelta);
- auto touchPoints = mapTouchPointIds(event->touchPoints());
+ auto touchPoints = mapTouchPointIds(event->points());
// Make sure that POINTER_DOWN action is delivered before MOVE, and MOVE before POINTER_UP
std::sort(touchPoints.begin(), touchPoints.end(), [] (const TouchPoint &l, const TouchPoint &r) {
return l.second.state() < r.second.state();
diff --git a/src/core/render_widget_host_view_qt_delegate_client.h b/src/core/render_widget_host_view_qt_delegate_client.h
index 0616dbc96..57354f549 100644
--- a/src/core/render_widget_host_view_qt_delegate_client.h
+++ b/src/core/render_widget_host_view_qt_delegate_client.h
@@ -46,7 +46,7 @@ struct MultipleMouseClickHelper
ulong lastPressTimestamp = 0;
};
-class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateClient
+class Q_WEBENGINECORE_EXPORT RenderWidgetHostViewQtDelegateClient
{
public:
RenderWidgetHostViewQtDelegateClient(RenderWidgetHostViewQt *rwhv);
diff --git a/src/core/render_widget_host_view_qt_delegate_item.cpp b/src/core/render_widget_host_view_qt_delegate_item.cpp
index dcf7e104c..23e5bc935 100644
--- a/src/core/render_widget_host_view_qt_delegate_item.cpp
+++ b/src/core/render_widget_host_view_qt_delegate_item.cpp
@@ -22,8 +22,10 @@ RenderWidgetHostViewQtDelegateItem::RenderWidgetHostViewQtDelegateItem(RenderWid
{
setFlag(ItemHasContents);
setAcceptedMouseButtons(Qt::AllButtons);
+ setKeepMouseGrab(true);
setAcceptHoverEvents(true);
setAcceptTouchEvents(true);
+ setKeepTouchGrab(true);
if (!isPopup) {
setFocus(true);
setActiveFocusOnTab(true);
@@ -33,7 +35,7 @@ RenderWidgetHostViewQtDelegateItem::RenderWidgetHostViewQtDelegateItem(RenderWid
RenderWidgetHostViewQtDelegateItem::~RenderWidgetHostViewQtDelegateItem()
{
- releaseVulkanResources();
+ releaseTextureResources();
if (m_widgetDelegate) {
m_widgetDelegate->Unbind();
m_widgetDelegate->Destroy();
@@ -204,6 +206,8 @@ void RenderWidgetHostViewQtDelegateItem::focusInEvent(QFocusEvent *event)
if (QAccessibleInterface *iface = QAccessible::queryAccessibleInterface(this)) {
if (auto *focusChild = iface->focusChild()) {
QAccessibleEvent focusEvent(focusChild, QAccessible::Focus);
+ if (focusEvent.object())
+ focusEvent.setChild(-1);
QAccessible::updateAccessibility(&focusEvent);
}
}
@@ -319,14 +323,16 @@ void RenderWidgetHostViewQtDelegateItem::itemChange(ItemChange change, const Ite
if (value.window) {
m_windowConnections.append(connect(value.window, &QQuickWindow::beforeRendering,
this, &RenderWidgetHostViewQtDelegateItem::onBeforeRendering, Qt::DirectConnection));
+ m_windowConnections.append(connect(value.window, &QQuickWindow::afterFrameEnd, this,
+ &RenderWidgetHostViewQtDelegateItem::onAfterFrameEnd,
+ Qt::DirectConnection));
m_windowConnections.append(connect(value.window, SIGNAL(xChanged(int)), SLOT(onWindowPosChanged())));
- m_windowConnections.append(connect(value.window, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged())));
-#if QT_CONFIG(webengine_vulkan)
+ m_windowConnections.append(
+ connect(value.window, SIGNAL(yChanged(int)), SLOT(onWindowPosChanged())));
m_windowConnections.append(
connect(value.window, &QQuickWindow::sceneGraphAboutToStop, this,
- &RenderWidgetHostViewQtDelegateItem::releaseVulkanResources,
+ &RenderWidgetHostViewQtDelegateItem::releaseTextureResources,
Qt::DirectConnection));
-#endif
if (!m_isPopup)
m_windowConnections.append(connect(value.window, SIGNAL(closing(QQuickCloseEvent *)), SLOT(onHide())));
}
@@ -346,15 +352,22 @@ QSGNode *RenderWidgetHostViewQtDelegateItem::updatePaintNode(QSGNode *oldNode, U
{
auto comp = compositor();
if (!comp)
- return nullptr;
+ return oldNode;
QQuickWindow *win = QQuickItem::window();
+ QSGImageNode *node = nullptr;
// Delete old node before swapFrame to decrement refcount of
// QImage in software mode.
- delete oldNode;
- QSGImageNode *node = win->createImageNode();
- node->setOwnsTexture(true);
+ if (comp->type() == Compositor::Type::Software)
+ delete oldNode;
+ else
+ node = static_cast<QSGImageNode*>(oldNode);
+
+ if (!node) {
+ node = win->createImageNode();
+ node->setOwnsTexture(true);
+ }
comp->swapFrame();
@@ -362,32 +375,22 @@ QSGNode *RenderWidgetHostViewQtDelegateItem::updatePaintNode(QSGNode *oldNode, U
QSizeF texSizeInDips = QSizeF(texSize) / comp->devicePixelRatio();
node->setRect(QRectF(QPointF(0, 0), texSizeInDips));
- if (comp->type() == Compositor::Type::Software) {
- QImage image = comp->image();
- node->setTexture(win->createTextureFromImage(image));
-#if QT_CONFIG(opengl)
- } else if (comp->type() == Compositor::Type::OpenGL) {
- QQuickWindow::CreateTextureOptions texOpts;
- if (comp->hasAlphaChannel())
- texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel);
- int texId = comp->textureId();
- node->setTexture(QNativeInterface::QSGOpenGLTexture::fromNative(texId, win, texSize, texOpts));
- node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
-#endif
-#if QT_CONFIG(webengine_vulkan)
- } else if (comp->type() == Compositor::Type::Vulkan) {
- QQuickWindow::CreateTextureOptions texOpts;
- if (comp->hasAlphaChannel())
- texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel);
-
- VkImage image = comp->vkImage(win);
- VkImageLayout layout = comp->vkImageLayout();
- node->setTexture(QNativeInterface::QSGVulkanTexture::fromNative(image, layout, win, texSize,
- texOpts));
- node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
-#endif // QT_CONFIG(webengine_vulkan)
+ QQuickWindow::CreateTextureOptions texOpts;
+ if (comp->requiresAlphaChannel() || m_clearColor.alpha() < 255)
+ texOpts.setFlag(QQuickWindow::TextureHasAlphaChannel);
+ else
+ texOpts.setFlag(QQuickWindow::TextureIsOpaque);
+ QSGTexture *texture = comp->texture(win, texOpts);
+ if (texture) {
+ node->setTexture(texture);
+ if (comp->textureIsFlipped())
+ node->setTextureCoordinatesTransform(QSGImageNode::MirrorVertically);
} else {
- Q_UNREACHABLE();
+ if (!oldNode || comp->type() == Compositor::Type::Software) {
+ qDebug("Compositor returned null texture");
+ delete node;
+ return nullptr;
+ }
}
return node;
@@ -401,6 +404,14 @@ void RenderWidgetHostViewQtDelegateItem::onBeforeRendering()
comp->waitForTexture();
}
+void RenderWidgetHostViewQtDelegateItem::onAfterFrameEnd()
+{
+ auto comp = compositor();
+ if (!comp || comp->type() != Compositor::Type::Native)
+ return;
+ comp->releaseTexture();
+}
+
void RenderWidgetHostViewQtDelegateItem::onWindowPosChanged()
{
m_client->visualPropertiesChanged();
@@ -412,15 +423,13 @@ void RenderWidgetHostViewQtDelegateItem::onHide()
m_client->forwardEvent(&event);
}
-void RenderWidgetHostViewQtDelegateItem::releaseVulkanResources()
+void RenderWidgetHostViewQtDelegateItem::releaseTextureResources()
{
-#if QT_CONFIG(webengine_vulkan)
auto comp = compositor();
- if (!comp || comp->type() != Compositor::Type::Vulkan)
+ if (!comp || comp->type() != Compositor::Type::Native)
return;
- comp->releaseVulkanResources(QQuickItem::window());
-#endif
+ comp->releaseResources();
}
void RenderWidgetHostViewQtDelegateItem::adapterClientChanged(WebContentsAdapterClient *client)
@@ -439,10 +448,8 @@ void RenderWidgetHostViewQtDelegateItem::updateAdapterClientIfNeeded(WebContents
void RenderWidgetHostViewQtDelegateItem::unhandledWheelEvent(QWheelEvent *ev)
{
- if (QWindow *w = Window()) {
- if (QWindow *p = w->parent())
- qApp->sendEvent(p, ev);
- }
+ if (m_widgetDelegate)
+ m_widgetDelegate->unhandledWheelEvent(ev);
}
} // namespace QtWebEngineCore
diff --git a/src/core/render_widget_host_view_qt_delegate_item.h b/src/core/render_widget_host_view_qt_delegate_item.h
index 6f3289157..0da6b4948 100644
--- a/src/core/render_widget_host_view_qt_delegate_item.h
+++ b/src/core/render_widget_host_view_qt_delegate_item.h
@@ -35,6 +35,7 @@ public:
virtual void Destroy() = 0;
virtual void Resize(int, int) { }
virtual QWindow *Window() { return nullptr; }
+ virtual void unhandledWheelEvent(QWheelEvent *) { }
};
// Useful information keyboard and mouse QEvent propagation.
@@ -43,7 +44,7 @@ public:
// but will still receive mouse input (all mouse QEvent moves and clicks will be given to the popup
// RWHVQD instance, and the mouse interaction area covers the surface of the whole parent
// QWebEngineView, and not only the smaller surface that an HTML select popup would occupy).
-class Q_WEBENGINECORE_PRIVATE_EXPORT RenderWidgetHostViewQtDelegateItem
+class Q_WEBENGINECORE_EXPORT RenderWidgetHostViewQtDelegateItem
: public QQuickItem
, public RenderWidgetHostViewQtDelegate
, public Compositor::Observer
@@ -100,8 +101,9 @@ protected:
private Q_SLOTS:
void onBeforeRendering();
+ void onAfterFrameEnd();
void onWindowPosChanged();
- void releaseVulkanResources();
+ void releaseTextureResources();
void onHide();
private:
diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp
index 80bbabf63..cc127e55f 100644
--- a/src/core/renderer/content_renderer_client_qt.cpp
+++ b/src/core/renderer/content_renderer_client_qt.cpp
@@ -10,8 +10,8 @@
#include "renderer/web_engine_page_render_frame.h"
#include "web_engine_library_info.h"
+#include "base/task/sequenced_task_runner.h"
#include "components/autofill/content/renderer/autofill_agent.h"
-#include "components/autofill/content/renderer/autofill_assistant_agent.h"
#include "components/autofill/content/renderer/password_autofill_agent.h"
#include "components/autofill/content/renderer/password_generation_agent.h"
#include "components/cdm/renderer/external_clear_key_key_system_info.h"
@@ -76,6 +76,7 @@
#include "content/public/renderer/key_system_support.h"
#include "media/base/media_switches.h"
#include "media/base/video_codecs.h"
+#include "media/cdm/clear_key_cdm_common.h"
#include "third_party/widevine/cdm/buildflags.h"
#if BUILDFLAG(ENABLE_WIDEVINE)
#include "third_party/widevine/cdm/widevine_cdm_common.h"
@@ -131,12 +132,12 @@ void ContentRendererClientQt::RenderThreadStarted()
void ContentRendererClientQt::ExposeInterfacesToBrowser(mojo::BinderMap* binders)
{
binders->Add<visitedlink::mojom::VisitedLinkNotificationSink>(
- m_visitedLinkReader->GetBindCallback(), base::SequencedTaskRunnerHandle::Get());
+ m_visitedLinkReader->GetBindCallback(), base::SingleThreadTaskRunner::GetCurrentDefault());
binders->Add<web_cache::mojom::WebCache>(
base::BindRepeating(&web_cache::WebCacheImpl::BindReceiver,
base::Unretained(m_webCacheImpl.get())),
- base::SequencedTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
#if QT_CONFIG(webengine_spellchecker)
binders->Add<spellcheck::mojom::SpellChecker>(
@@ -147,7 +148,7 @@ void ContentRendererClientQt::ExposeInterfacesToBrowser(mojo::BinderMap* binders
client->InitSpellCheck();
client->m_spellCheck->BindReceiver(std::move(receiver));
}, this),
- base::SequencedTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
#endif
#if QT_CONFIG(webengine_webrtc) && QT_CONFIG(webengine_extensions)
@@ -157,7 +158,7 @@ void ContentRendererClientQt::ExposeInterfacesToBrowser(mojo::BinderMap* binders
mojo::PendingReceiver<chrome::mojom::WebRtcLoggingAgent> receiver) {
client->GetWebRtcLoggingAgent()->AddReceiver(std::move(receiver));
}, this),
- base::SequencedTaskRunnerHandle::Get());
+ base::SingleThreadTaskRunner::GetCurrentDefault());
#endif
}
@@ -195,8 +196,6 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame *render_fr
ExtensionsRendererClientQt::GetInstance()->RenderFrameCreated(render_frame, render_frame_observer->registry());
#endif
- autofill::AutofillAssistantAgent *autofill_assistant_agent =
- new autofill::AutofillAssistantAgent(render_frame);
autofill::PasswordAutofillAgent *password_autofill_agent =
new autofill::PasswordAutofillAgent(render_frame, associated_interfaces);
autofill::PasswordGenerationAgent *password_generation_agent =
@@ -204,7 +203,7 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame *render_fr
associated_interfaces);
new autofill::AutofillAgent(render_frame, password_autofill_agent, password_generation_agent,
- autofill_assistant_agent, associated_interfaces);
+ associated_interfaces);
}
void ContentRendererClientQt::WebViewCreated(blink::WebView *web_view,
@@ -290,11 +289,12 @@ void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderF
// TODO(elproxy): We could potentially get better diagnostics here by first calling
// NetErrorHelper::GetErrorStringsForDnsProbe, but that one is harder to untangle.
+ base::Value::Dict error_page_params;
error_page::LocalizedError::PageState errorPageState =
error_page::LocalizedError::GetPageState(
error.reason(), error.domain(), error.url(), isPost, false,
error.stale_copy_in_cache(), false,
- RenderConfiguration::is_incognito_process(), false, false, false, locale, false);
+ RenderConfiguration::is_incognito_process(), false, false, false, locale, false, &error_page_params);
resourceId = IDR_NET_ERROR_HTML;
@@ -473,11 +473,9 @@ void ContentRendererClientQt::GetInterface(const std::string &interface_name, mo
// found in the LICENSE.Chromium file.
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
-static const char kExternalClearKeyKeySystem[] = "org.chromium.externalclearkey";
-
// External Clear Key (used for testing).
static void AddExternalClearKey(const media::mojom::KeySystemCapabilityPtr &capability,
- media::KeySystemInfoVector *key_systems)
+ media::KeySystemInfos* key_systems)
{
Q_UNUSED(capability);
if (!base::FeatureList::IsEnabled(media::kExternalClearKeyForTesting)) {
@@ -486,7 +484,7 @@ static void AddExternalClearKey(const media::mojom::KeySystemCapabilityPtr &capa
}
// TODO(xhwang): Actually use `capability` to determine capabilities.
- key_systems->push_back(std::make_unique<cdm::ExternalClearKeyProperties>());
+ key_systems->push_back(std::make_unique<cdm::ExternalClearKeyKeySystemInfo>());
}
#if BUILDFLAG(ENABLE_WIDEVINE)
@@ -603,7 +601,7 @@ static media::SupportedCodecs GetSupportedCodecs(const media::CdmCapability& cap
}
static void AddWidevine(const media::mojom::KeySystemCapabilityPtr &capability,
- media::KeySystemInfoVector *key_systems)
+ media::KeySystemInfos *key_systems)
{
// Codecs and encryption schemes.
media::SupportedCodecs codecs = media::EME_CODEC_NONE;
@@ -658,11 +656,11 @@ static void AddWidevine(const media::mojom::KeySystemCapabilityPtr &capability,
void OnKeySystemSupportUpdated(media::GetSupportedKeySystemsCB cb,
content::KeySystemCapabilityPtrMap key_system_capabilities)
{
- media::KeySystemInfoVector key_systems;
+ media::KeySystemInfos key_systems;
for (const auto &entry : key_system_capabilities) {
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
const auto &key_system = entry.first;
const auto &capability = entry.second;
-#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#if BUILDFLAG(ENABLE_WIDEVINE)
if (key_system == kWidevineKeySystem) {
AddWidevine(capability, &key_systems);
@@ -670,13 +668,13 @@ void OnKeySystemSupportUpdated(media::GetSupportedKeySystemsCB cb,
}
#endif // BUILDFLAG(ENABLE_WIDEVINE)
- if (key_system == kExternalClearKeyKeySystem) {
+ if (key_system == media::kExternalClearKeyKeySystem) {
AddExternalClearKey(capability, &key_systems);
continue;
}
-#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
DLOG(ERROR) << "Unrecognized key system: " << key_system;
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
}
cb.Run(std::move(key_systems));
diff --git a/src/core/renderer/extensions/resource_request_policy_qt.cpp b/src/core/renderer/extensions/resource_request_policy_qt.cpp
index 21b7be4b6..a61e53310 100644
--- a/src/core/renderer/extensions/resource_request_policy_qt.cpp
+++ b/src/core/renderer/extensions/resource_request_policy_qt.cpp
@@ -27,8 +27,9 @@ ResourceRequestPolicyQt::ResourceRequestPolicyQt(Dispatcher *dispatcher)
void ResourceRequestPolicyQt::OnExtensionLoaded(const Extension &extension)
{
- if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension)
- || WebviewInfo::HasWebviewAccessibleResources(extension, m_dispatcher->webview_partition_id())
+ if (WebAccessibleResourcesInfo::HasWebAccessibleResources(&extension) ||
+ WebviewInfo::HasWebviewAccessibleResources(extension,
+ m_dispatcher->webview_partition_id().value_or(std::string()))
// // Hosted app icons are accessible.
// // TODO(devlin): Should we incorporate this into
// // WebAccessibleResourcesInfo?
@@ -131,7 +132,9 @@ bool ResourceRequestPolicyQt::CanRequestResource(const GURL &resource_url,
// Disallow loading of extension resources which are not explicitly listed
// as web or WebView accessible if the manifest version is 2 or greater.
if (!WebAccessibleResourcesInfo::IsResourceWebAccessible(extension, resource_url.path(), initiator_origin) &&
- !WebviewInfo::IsResourceWebviewAccessible(extension, m_dispatcher->webview_partition_id(), resource_url.path()))
+ !WebviewInfo::IsResourceWebviewAccessible(extension,
+ m_dispatcher->webview_partition_id().value_or(std::string()),
+ resource_url.path()))
{
std::string message = base::StringPrintf(
"Denying load of %s. Resources must be listed in the "
diff --git a/src/core/renderer/plugins/loadable_plugin_placeholder_qt.h b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.h
index fd808f766..9b9d1bca8 100644
--- a/src/core/renderer/plugins/loadable_plugin_placeholder_qt.h
+++ b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.h
@@ -31,8 +31,6 @@ private:
// content::LoadablePluginPlaceholder overrides.
blink::WebPlugin* CreatePlugin() override;
- void OnBlockedContent(content::RenderFrame::PeripheralContentStatus status,
- bool is_same_origin) override {}
// WebViewPlugin::Delegate (via PluginPlaceholder) methods:
v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) override;
diff --git a/src/core/renderer/print_web_view_helper_delegate_qt.cpp b/src/core/renderer/print_web_view_helper_delegate_qt.cpp
index f77b6fbbc..f01568e65 100644
--- a/src/core/renderer/print_web_view_helper_delegate_qt.cpp
+++ b/src/core/renderer/print_web_view_helper_delegate_qt.cpp
@@ -15,8 +15,10 @@
#include "chrome/common/webui_url_constants.h"
#include "extensions/common/constants.h"
#include "third_party/blink/public/web/web_document.h"
+#include "extensions/renderer/guest_view/mime_handler_view/post_message_support.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
+#include "pdf_util_qt.h"
#include "print_web_view_helper_delegate_qt.h"
#include "web_engine_library_info.h"
@@ -24,33 +26,13 @@ namespace QtWebEngineCore {
PrintWebViewHelperDelegateQt::~PrintWebViewHelperDelegateQt() {}
-bool IsPdfExtensionOrigin(const url::Origin& origin)
-{
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- return origin.scheme() == extensions::kExtensionScheme
- && origin.host() == extension_misc::kPdfExtensionId;
-#else
- Q_UNUSED(origin);
- return false;
-#endif
-}
-
blink::WebElement PrintWebViewHelperDelegateQt::GetPdfElement(blink::WebLocalFrame *frame)
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
- const url::Origin origin = frame->GetDocument().GetSecurityOrigin();
- bool inside_print_preview = origin == url::Origin::Create(GURL(chrome::kChromeUIPrintURL));
- bool inside_pdf_extension = IsPdfExtensionOrigin(origin);
- if (inside_print_preview || inside_pdf_extension) {
- // <object> with id="plugin" is created in
- // chrome/browser/resources/pdf/pdf_viewer_base.js.
- auto viewer_element = frame->GetDocument().GetElementById("viewer");
- if (!viewer_element.IsNull() && !viewer_element.ShadowRoot().IsNull()) {
- auto plugin_element = viewer_element.ShadowRoot().QuerySelector("#plugin");
- if (!plugin_element.IsNull())
- return plugin_element;
- }
- NOTREACHED();
+ if (frame->Parent() && IsPdfInternalPluginAllowedOrigin(frame->Parent()->GetSecurityOrigin())) {
+ auto plugin_element = frame->GetDocument().QuerySelector("embed");
+ DCHECK(!plugin_element.IsNull());
+ return plugin_element;
}
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
return blink::WebElement();
diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp
index c49ecd391..eff304981 100644
--- a/src/core/renderer/user_resource_controller.cpp
+++ b/src/core/renderer/user_resource_controller.cpp
@@ -5,6 +5,7 @@
#include "base/memory/weak_ptr.h"
#include "base/strings/pattern.h"
+#include "base/task/single_thread_task_runner.h"
#include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_frame_observer.h"
#include "extensions/common/url_pattern.h"
@@ -203,7 +204,7 @@ void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad
m_runner.reset(new Runner(render_frame()->GetWebFrame(), m_userResourceController));
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&Runner::run, m_runner->AsWeakPtr(),
QtWebEngineCore::UserScriptData::DocumentElementCreation));
@@ -214,7 +215,7 @@ void UserResourceController::RenderFrameObserverHelper::DidDispatchDOMContentLoa
// Don't run scripts if provisional load failed (DidFailProvisionalLoad
// called instead of DidCommitProvisionalLoad).
if (m_runner)
- base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&Runner::run, m_runner->AsWeakPtr(),
QtWebEngineCore::UserScriptData::AfterLoad),
@@ -224,7 +225,7 @@ void UserResourceController::RenderFrameObserverHelper::DidDispatchDOMContentLoa
void UserResourceController::RenderFrameObserverHelper::DidFinishLoad()
{
if (m_runner)
- base::ThreadTaskRunnerHandle::Get()->PostTask(
+ base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
FROM_HERE,
base::BindOnce(&Runner::run, m_runner->AsWeakPtr(),
QtWebEngineCore::UserScriptData::AfterLoad));
@@ -289,10 +290,11 @@ void UserResourceController::renderFrameDestroyed(content::RenderFrame *renderFr
FrameUserScriptMap::iterator it = m_frameUserScriptMap.find(renderFrame);
if (it == m_frameUserScriptMap.end()) // ASSERT maybe?
return;
- for (uint64_t id : std::as_const(it.value())) {
- m_scripts.remove(id);
+ if (renderFrame->IsMainFrame()) {
+ for (uint64_t id : std::as_const(it.value()))
+ m_scripts.remove(id);
}
- m_frameUserScriptMap.remove(renderFrame);
+ m_frameUserScriptMap.erase(it);
}
void UserResourceController::addScriptForFrame(const QtWebEngineCore::UserScriptData &script,
@@ -304,7 +306,8 @@ void UserResourceController::addScriptForFrame(const QtWebEngineCore::UserScript
if (!(*it).contains(script.scriptId))
(*it).append(script.scriptId);
- m_scripts.insert(script.scriptId, script);
+ if (!frame || frame->IsMainFrame())
+ m_scripts.insert(script.scriptId, script);
}
void UserResourceController::removeScriptForFrame(const QtWebEngineCore::UserScriptData &script,
@@ -315,7 +318,8 @@ void UserResourceController::removeScriptForFrame(const QtWebEngineCore::UserScr
return;
(*it).removeOne(script.scriptId);
- m_scripts.remove(script.scriptId);
+ if (!frame || frame->IsMainFrame())
+ m_scripts.remove(script.scriptId);
}
void UserResourceController::clearScriptsForFrame(content::RenderFrame *frame)
@@ -323,8 +327,10 @@ void UserResourceController::clearScriptsForFrame(content::RenderFrame *frame)
FrameUserScriptMap::iterator it = m_frameUserScriptMap.find(frame);
if (it == m_frameUserScriptMap.end())
return;
- for (uint64_t id : std::as_const(it.value()))
- m_scripts.remove(id);
+ if (!frame || frame->IsMainFrame()) {
+ for (uint64_t id : std::as_const(it.value()))
+ m_scripts.remove(id);
+ }
m_frameUserScriptMap.remove(frame);
}
diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp
index 04a4ce705..89b20c7d1 100644
--- a/src/core/renderer/web_channel_ipc_transport.cpp
+++ b/src/core/renderer/web_channel_ipc_transport.cpp
@@ -43,8 +43,6 @@ void WebChannelTransport::Install(blink::WebLocalFrame *frame, uint worldId)
{
v8::Isolate *isolate = blink::MainThreadIsolate();
v8::HandleScope handleScope(isolate);
- v8::MicrotasksScope microtasks_scope(
- isolate, v8::MicrotasksScope::kDoNotRunMicrotasks);
v8::Local<v8::Context> context;
if (worldId == 0)
context = frame->MainWorldScriptContext();
@@ -59,15 +57,14 @@ void WebChannelTransport::Install(blink::WebLocalFrame *frame, uint worldId)
return;
v8::Local<v8::Object> global = context->Global();
- v8::Local<v8::Value> qtObjectValue;
v8::Local<v8::Object> qtObject;
- if (!global->Get(context, gin::StringToV8(isolate, "qt")).ToLocal(&qtObjectValue) || !qtObjectValue->IsObject()) {
- qtObject = v8::Object::New(isolate);
- global->Set(context, gin::StringToV8(isolate, "qt"), qtObject).Check();
- } else {
- qtObject = v8::Local<v8::Object>::Cast(qtObjectValue);
- }
- qtObject->Set(context, gin::StringToV8(isolate, "webChannelTransport"), transport.ToV8()).Check();
+ qtObject = v8::Object::New(isolate);
+ global->CreateDataProperty(context,
+ gin::StringToSymbol(isolate, "qt"),
+ qtObject).Check();
+ qtObject->CreateDataProperty(context,
+ gin::StringToSymbol(isolate, "webChannelTransport"),
+ transport.ToV8()).Check();
}
void WebChannelTransport::Uninstall(blink::WebLocalFrame *frame, uint worldId)
diff --git a/src/core/renderer_host/user_resource_controller_host.h b/src/core/renderer_host/user_resource_controller_host.h
index e92deb900..eb4404879 100644
--- a/src/core/renderer_host/user_resource_controller_host.h
+++ b/src/core/renderer_host/user_resource_controller_host.h
@@ -47,7 +47,7 @@ using UserResourceControllerRemote = mojo::AssociatedRemote<qtwebengine::mojom::
using UserResourceControllerRenderFrameRemote = mojo::AssociatedRemote<qtwebengine::mojom::UserResourceControllerRenderFrame>;
class WebContentsAdapter;
-class Q_WEBENGINECORE_PRIVATE_EXPORT UserResourceControllerHost
+class Q_WEBENGINECORE_EXPORT UserResourceControllerHost
{
public:
diff --git a/src/core/select_file_dialog_factory_qt.cpp b/src/core/select_file_dialog_factory_qt.cpp
index 9da27a4cf..1f897a805 100644
--- a/src/core/select_file_dialog_factory_qt.cpp
+++ b/src/core/select_file_dialog_factory_qt.cpp
@@ -137,7 +137,7 @@ SelectFileDialogFactoryQt::Create(ui::SelectFileDialog::Listener *listener,
std::unique_ptr<ui::SelectFilePolicy> policy)
{
content::WebContents *webContents =
- static_cast<SelectFilePolicyQt *>(policy.get())->webContents();
+ static_cast<SelectFilePolicyQt *>(policy.get())->webContents()->GetOutermostWebContents();
WebContentsAdapterClient *client =
WebContentsViewQt::from(static_cast<content::WebContentsImpl *>(webContents)->GetView())
->client();
diff --git a/src/core/tools/CMakeLists.txt b/src/core/tools/qwebengine_convert_dict/CMakeLists.txt
index 9029b60a1..5e8a1de14 100644
--- a/src/core/tools/CMakeLists.txt
+++ b/src/core/tools/qwebengine_convert_dict/CMakeLists.txt
@@ -1,11 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
-
-##
-# WEBENGINECORE DICT CONVERT TOOL
-##
-
if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING)
qt_get_tool_target_name(dict_target_name qwebengine_convert_dict)
qt_internal_add_tool(${dict_target_name}
@@ -14,7 +9,7 @@ if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING)
TOOLS_TARGET WebEngineCore
SOURCES main.cpp
INCLUDE_DIRECTORIES
- ../../3rdparty/chromium/third_party/abseil-cpp
+ ../../../3rdparty/chromium/third_party/abseil-cpp
)
if(COMMAND qt_internal_return_unless_building_tools)
qt_internal_return_unless_building_tools()
@@ -22,11 +17,12 @@ if(QT_FEATURE_webengine_spellchecker AND NOT CMAKE_CROSSCOMPILING)
qt_skip_warnings_are_errors(${dict_target_name})
add_dependencies(${dict_target_name} WebEngineCore)
qt_internal_extend_target(${dict_target_name} CONDITION WIN32
- DEFINES WIN32_LEAN_AND_MEAN NOMINMAX
+ DEFINES WIN32_LEAN_AND_MEAN
)
qt_internal_extend_target(${dict_target_name} CONDITION GCC OR CLANG
COMPILE_OPTIONS -Wno-unused-parameter
)
+ set_target_properties(${dict_target_name} PROPERTIES CXX_STANDARD 20)
if(NOT QT_FEATURE_webengine_system_icu AND QT_WILL_INSTALL)
# tool can be called durig build so copy icu file
get_target_property(icuFile WebEngineCore ICUDTL_FILE)
diff --git a/src/core/tools/main.cpp b/src/core/tools/qwebengine_convert_dict/main.cpp
index 4b6c82997..a82947ddc 100644
--- a/src/core/tools/main.cpp
+++ b/src/core/tools/qwebengine_convert_dict/main.cpp
@@ -111,7 +111,7 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words,
}
base::span<const int> expectedAffixes(org_words[i].second);
- base::span<const int> actualAffixes(affix_ids, affix_matches);
+ base::span<const int> actualAffixes(affix_ids, (size_t)affix_matches);
if (!std::equal(expectedAffixes.begin(), expectedAffixes.end(),
actualAffixes.begin(), actualAffixes.end(),
diff --git a/src/core/tools/webenginedriver/CMakeLists.txt b/src/core/tools/webenginedriver/CMakeLists.txt
new file mode 100644
index 000000000..b20311980
--- /dev/null
+++ b/src/core/tools/webenginedriver/CMakeLists.txt
@@ -0,0 +1,57 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+if(WIN32)
+ set(WEBENGINEDRIVER_EXECUTABLE webenginedriver.exe)
+else()
+ set(WEBENGINEDRIVER_EXECUTABLE webenginedriver)
+endif()
+set(WEBENGINEDRIVER_EXECUTABLE ${WEBENGINEDRIVER_EXECUTABLE} PARENT_SCOPE)
+
+if(QT_FEATURE_webenginedriver)
+ get_install_config(config)
+ get_architectures(archs)
+ list(GET archs 0 arch)
+
+ ##
+ # DOCS
+ ##
+ add_code_attributions_target(
+ TARGET generate_webenginedriver_attributions
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/webenginedriver_attributions.qdoc
+ GN_TARGET //chrome/test/chromedriver:chromedriver_server
+ EXTRA_THIRD_PARTY_DIRS
+ third_party/selenium-atoms/sizzle
+ third_party/selenium-atoms/wgxpath
+ third_party/selenium-atoms/closure-lib
+ FILE_TEMPLATE ../../doc/about_credits.tmpl
+ ENTRY_TEMPLATE ../../doc/about_credits_entry.tmpl
+ BUILDDIR ${buildDir}/${config}/${arch}
+ )
+ add_dependencies(generate_webenginedriver_attributions run_core_GnDone)
+ add_dependencies(prepare_docs_WebEngineCore generate_webenginedriver_attributions)
+
+ ##
+ # INSTALL
+ ##
+ install(
+ PROGRAMS ${buildDir}/${config}/${arch}/${WEBENGINEDRIVER_EXECUTABLE}
+ CONFIGURATIONS ${config}
+ RUNTIME DESTINATION "${INSTALL_LIBEXECDIR}"
+ )
+ if(NOT QT_WILL_INSTALL)
+ add_custom_target(copy-webenginedriver
+ ALL
+ DEPENDS ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${WEBENGINEDRIVER_EXECUTABLE}
+ )
+ add_custom_command(
+ OUTPUT ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}/${WEBENGINEDRIVER_EXECUTABLE}
+ COMMAND ${CMAKE_COMMAND} -E copy ${buildDir}/${config}/${arch}/${WEBENGINEDRIVER_EXECUTABLE}
+ ${QT_BUILD_DIR}/${INSTALL_LIBEXECDIR}
+ DEPENDS
+ WebEngineCore
+ ${buildDir}/${config}/${arch}/${WEBENGINEDRIVER_EXECUTABLE}
+ USES_TERMINAL
+ )
+ endif()
+endif()
diff --git a/src/core/touch_handle_drawable_client.h b/src/core/touch_handle_drawable_client.h
index 3e1812a35..ddfaa9f57 100644
--- a/src/core/touch_handle_drawable_client.h
+++ b/src/core/touch_handle_drawable_client.h
@@ -9,7 +9,7 @@
namespace QtWebEngineCore {
-class Q_WEBENGINECORE_PRIVATE_EXPORT TouchHandleDrawableDelegate {
+class Q_WEBENGINECORE_EXPORT TouchHandleDrawableDelegate {
public:
virtual ~TouchHandleDrawableDelegate() { }
diff --git a/src/core/touch_selection_controller_client_qt.h b/src/core/touch_selection_controller_client_qt.h
index df693a0e1..3fdca7922 100644
--- a/src/core/touch_selection_controller_client_qt.h
+++ b/src/core/touch_selection_controller_client_qt.h
@@ -51,6 +51,9 @@ public:
ui::TouchSelectionController* GetTouchSelectionController() override;
void AddObserver(Observer* observer) override;
void RemoveObserver(Observer* observer) override;
+ void OnSwipeToMoveCursorBegin() override {}
+ void OnSwipeToMoveCursorEnd() override {}
+ void OnClientHitTestRegionUpdated(ui::TouchSelectionControllerClient *) override {}
// ui::TouchSelectionControllerClient overrides
bool SupportsAnimation() const override;
diff --git a/src/core/touch_selection_menu_controller.h b/src/core/touch_selection_menu_controller.h
index 184ac039b..6a1fc1960 100644
--- a/src/core/touch_selection_menu_controller.h
+++ b/src/core/touch_selection_menu_controller.h
@@ -11,7 +11,7 @@ namespace QtWebEngineCore {
class TouchSelectionControllerClientQt;
-class Q_WEBENGINECORE_PRIVATE_EXPORT TouchSelectionMenuController : public QObject {
+class Q_WEBENGINECORE_EXPORT TouchSelectionMenuController : public QObject {
Q_OBJECT
public:
enum TouchSelectionCommandFlag {
diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp
index 54f6e2e4f..2d4fb323d 100644
--- a/src/core/type_conversion.cpp
+++ b/src/core/type_conversion.cpp
@@ -103,6 +103,7 @@ QImage toQImage(const SkBitmap &bitmap)
}
break;
case kBGR_101010x_SkColorType:
+ case kBGR_101010x_XR_SkColorType:
case kBGRA_1010102_SkColorType:
switch (bitmap.alphaType()) {
case kUnknown_SkAlphaType:
diff --git a/src/core/type_conversion.h b/src/core/type_conversion.h
index 92304a7b8..0da8a6931 100644
--- a/src/core/type_conversion.h
+++ b/src/core/type_conversion.h
@@ -58,11 +58,21 @@ inline QString toQt(const absl::optional<std::u16string> &string)
return QString::fromStdU16String(*string);
}
+inline QString toQString(const base::StringPiece &string)
+{
+ return QString::fromUtf8(string.data(), string.size());
+}
+
inline QString toQString(const std::string &string)
{
return QString::fromStdString(string);
}
+inline QByteArray toQByteArray(const base::StringPiece &string)
+{
+ return QByteArray(string.data(), string.size());
+}
+
inline QByteArray toQByteArray(const std::string &string)
{
return QByteArray::fromStdString(string);
diff --git a/src/core/visited_links_manager_qt.h b/src/core/visited_links_manager_qt.h
index eff124bfd..7bcf32d52 100644
--- a/src/core/visited_links_manager_qt.h
+++ b/src/core/visited_links_manager_qt.h
@@ -32,7 +32,7 @@ namespace QtWebEngineCore {
class ProfileQt;
class VisitedLinkDelegateQt;
-class Q_WEBENGINECORE_PRIVATE_EXPORT VisitedLinksManagerQt {
+class Q_WEBENGINECORE_EXPORT VisitedLinksManagerQt {
public:
virtual~VisitedLinksManagerQt();
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 081505d7f..7ffeaaa5b 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -15,6 +15,7 @@
#include "favicon_service_factory_qt.h"
#include "find_text_helper.h"
#include "media_capture_devices_dispatcher.h"
+#include "pdf_util_qt.h"
#include "profile_adapter.h"
#include "profile_qt.h"
#include "qwebengineloadinginfo.h"
@@ -39,7 +40,6 @@
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/text_input_manager.h"
#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/download_request_utils.h"
@@ -60,6 +60,7 @@
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/gfx/font_render_params.h"
+#include "ui/native_theme/native_theme.h"
#include "qtwebengine/browser/qtwebenginepage.mojom.h"
#include <QtCore/QVariant>
@@ -80,8 +81,6 @@
#endif
#if QT_CONFIG(webengine_printing_and_pdf)
-#include "components/pdf/browser/pdf_web_contents_helper.h"
-#include "printing/pdf_web_contents_helper_client_qt.h"
#include "printing/print_view_manager_qt.h"
#endif
@@ -152,7 +151,7 @@ static QVariant fromJSValue(const base::Value *result)
}
break;
}
- case base::Value::Type::DICTIONARY:
+ case base::Value::Type::DICT:
{
if (const auto dict = result->GetIfDict()) {
QVariantMap map;
@@ -210,10 +209,28 @@ static std::unique_ptr<content::WebContents> createBlankWebContents(WebContentsA
return webContents;
}
+static int navigationListSize(content::NavigationController &controller) {
+ // If we're currently on the initial NavigationEntry, no navigation has
+ // committed, so the initial NavigationEntry should not be part of the
+ // "Navigation List", and we should return 0 as the navigation list size.
+ if (controller.GetLastCommittedEntry()->IsInitialEntry())
+ return 0;
+ return controller.GetEntryCount();
+}
+
+static int navigationListCurrentIndex(content::NavigationController &controller) {
+ // If we're currently on the initial NavigationEntry, no navigation has
+ // committed, so the initial NavigationEntry should not be part of the
+ // "Navigation List", and we should return -1 as the current index.
+ if (controller.GetLastCommittedEntry()->IsInitialEntry())
+ return -1;
+ return controller.GetCurrentEntryIndex();
+}
+
static void serializeNavigationHistory(content::NavigationController &controller, QDataStream &output)
{
- const int currentIndex = controller.GetCurrentEntryIndex();
- const int count = controller.GetEntryCount();
+ const int currentIndex = navigationListCurrentIndex(controller);
+ const int count = navigationListSize(controller);
const int pendingIndex = controller.GetPendingEntryIndex();
output << kHistoryStreamVersion;
@@ -262,7 +279,7 @@ static void deserializeNavigationHistory(QDataStream &input, int *currentIndex,
int count;
input >> count >> *currentIndex;
- std::unique_ptr<content::NavigationEntryRestoreContext> context = content::NavigationEntryRestoreContext::Create(); // FIXME?
+ std::unique_ptr<content::NavigationEntryRestoreContext> context = content::NavigationEntryRestoreContext::Create();
entries->reserve(count);
// Logic taken from SerializedNavigationEntry::ReadFromPickle and ToNavigationEntries.
@@ -304,6 +321,7 @@ static void deserializeNavigationHistory(QDataStream &input, int *currentIndex,
toGurl(virtualUrl),
content::Referrer(toGurl(referrerUrl), static_cast<network::mojom::ReferrerPolicy>(referrerPolicy)),
absl::nullopt, // optional initiator_origin
+ absl::nullopt, // optional initiator_base_url
// Use a transition type of reload so that we don't incorrectly
// increase the typed count.
ui::PAGE_TRANSITION_RELOAD,
@@ -389,17 +407,6 @@ QSharedPointer<WebContentsAdapter> WebContentsAdapter::createFromSerializedNavig
content::NavigationController &controller = newWebContents->GetController();
controller.Restore(currentIndex, content::RestoreType::kRestored, &entries);
- if (controller.GetActiveEntry()) {
- // Set up the file access rights for the selected navigation entry.
- // TODO(joth): This is duplicated from chrome/.../session_restore.cc and
- // should be shared e.g. in NavigationController. http://crbug.com/68222
- const int id = newWebContents->GetPrimaryMainFrame()->GetProcess()->GetID();
- const blink::PageState& pageState = controller.GetActiveEntry()->GetPageState();
- const std::vector<base::FilePath>& filePaths = pageState.GetReferencedFiles();
- for (std::vector<base::FilePath>::const_iterator file = filePaths.begin(); file != filePaths.end(); ++file)
- content::ChildProcessSecurityPolicy::GetInstance()->GrantReadFile(id, *file);
- }
-
return QSharedPointer<WebContentsAdapter>::create(std::move(newWebContents));
}
@@ -447,6 +454,10 @@ bool WebContentsAdapter::isInitialized() const
return (bool)m_webContentsDelegate;
}
+ui::NativeTheme::PreferredColorScheme toWeb(Qt::ColorScheme colorScheme) {
+ return colorScheme == Qt::ColorScheme::Dark ? ui::NativeTheme::PreferredColorScheme::kDark : ui::NativeTheme::PreferredColorScheme::kLight;
+}
+
void WebContentsAdapter::initialize(content::SiteInstance *site)
{
Q_ASSERT(m_adapterClient);
@@ -484,14 +495,6 @@ void WebContentsAdapter::initialize(content::SiteInstance *site)
webContents(), FaviconServiceFactoryQt::GetForBrowserContext(context), m_adapterClient);
AutofillClientQt::CreateForWebContents(webContents());
- autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
- webContents(), AutofillClientQt::FromWebContents(webContents()),
- base::BindRepeating(&autofill::BrowserDriverInitHook, AutofillClientQt::FromWebContents(webContents()), ""));
-
-#if QT_CONFIG(webengine_printing_and_pdf) && QT_CONFIG(webengine_extensions)
- pdf::PDFWebContentsHelper::CreateForWebContentsWithClient(
- webContents(), std::make_unique<PDFWebContentsHelperClientQt>());
-#endif
// Create an instance of WebEngineVisitedLinksManager to catch the first
// content::NOTIFICATION_RENDERER_PROCESS_CREATED event. This event will
@@ -508,6 +511,12 @@ void WebContentsAdapter::initialize(content::SiteInstance *site)
m_webContentsDelegate->RenderViewHostChanged(nullptr, rvh);
+ // Make sure the system theme's light/dark mode is propagated to webpages
+ QObject::connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, [](Qt::ColorScheme colorScheme){
+ ui::NativeTheme::GetInstanceForWeb()->set_preferred_color_scheme(toWeb(colorScheme));
+ });
+ ui::NativeTheme::GetInstanceForWeb()->set_preferred_color_scheme(toWeb(QGuiApplication::styleHints()->colorScheme()));
+
m_adapterClient->initializationFinished();
}
@@ -521,7 +530,7 @@ void WebContentsAdapter::initializeRenderPrefs()
rendererPrefs->caret_blink_interval =
base::Milliseconds(0.5 * static_cast<double>(qtCursorFlashTime));
rendererPrefs->user_agent_override = blink::UserAgentOverride::UserAgentOnly(m_profileAdapter->httpUserAgent().toStdString());
- rendererPrefs->user_agent_override.ua_metadata_override = ContentBrowserClientQt::getUserAgentMetadata();
+ rendererPrefs->user_agent_override.ua_metadata_override = profile()->userAgentMetadata();
rendererPrefs->accept_languages = m_profileAdapter->httpAcceptLanguageWithoutQualities().toStdString();
#if QT_CONFIG(webengine_webrtc)
base::CommandLine* commandLine = base::CommandLine::ForCurrentProcess();
@@ -535,6 +544,8 @@ void WebContentsAdapter::initializeRenderPrefs()
? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly
: blink::kWebRTCIPHandlingDefault;
#endif
+ rendererPrefs->can_accept_load_drops = m_adapterClient->webEngineSettings()->testAttribute(QWebEngineSettings::NavigateOnDropEnabled);
+
// Set web-contents font settings to the default font settings as Chromium constantly overrides
// the global font defaults with the font settings of the latest web-contents created.
static const gfx::FontRenderParams params = gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr);
@@ -753,7 +764,7 @@ void WebContentsAdapter::save(const QString &filePath, int savePageFormat)
{
CHECK_INITIALIZED();
base::RecordAction(base::UserMetricsAction("SavePage"));
- m_webContentsDelegate->setSavePageInfo(SavePageInfo(filePath, savePageFormat));
+ m_webContentsDelegate->setSavePageInfo(new SavePageInfo(filePath, savePageFormat));
m_webContents->OnSavePage();
}
@@ -909,13 +920,13 @@ void WebContentsAdapter::navigateToOffset(int offset)
int WebContentsAdapter::navigationEntryCount()
{
CHECK_INITIALIZED(0);
- return m_webContents->GetController().GetEntryCount();
+ return navigationListSize(m_webContents->GetController());
}
int WebContentsAdapter::currentNavigationEntryIndex()
{
CHECK_INITIALIZED(0);
- return m_webContents->GetController().GetCurrentEntryIndex();
+ return navigationListCurrentIndex(m_webContents->GetController());
}
QUrl WebContentsAdapter::getNavigationEntryOriginalUrl(int index)
@@ -979,9 +990,8 @@ void WebContentsAdapter::setZoomFactor(qreal factor)
content::HostZoomMap *zoomMap = content::HostZoomMap::GetForWebContents(m_webContents.get());
if (zoomMap) {
- int render_process_id = m_webContents->GetPrimaryMainFrame()->GetProcess()->GetID();
- int render_view_id = m_webContents->GetRenderViewHost()->GetRoutingID();
- zoomMap->SetTemporaryZoomLevel(render_process_id, render_view_id, zoomLevel);
+ const content::GlobalRenderFrameHostId global_id = m_webContents->GetPrimaryMainFrame()->GetGlobalId();
+ zoomMap->SetTemporaryZoomLevel(global_id, zoomLevel);
}
}
@@ -1034,6 +1044,10 @@ void WebContentsAdapter::runJavaScript(const QString &javaScript, quint32 worldI
CHECK_INITIALIZED();
content::RenderFrameHost *rfh = m_webContents->GetPrimaryMainFrame();
Q_ASSERT(rfh);
+ if (!static_cast<content::RenderFrameHostImpl*>(rfh)->GetAssociatedLocalFrame()) {
+ qWarning() << "Local frame is gone, not running script";
+ return;
+ }
if (worldId == 0)
rfh->ExecuteJavaScript(toString16(javaScript), base::NullCallback());
else
@@ -1045,6 +1059,10 @@ quint64 WebContentsAdapter::runJavaScriptCallbackResult(const QString &javaScrip
CHECK_INITIALIZED(0);
content::RenderFrameHost *rfh = m_webContents->GetPrimaryMainFrame();
Q_ASSERT(rfh);
+ if (!static_cast<content::RenderFrameHostImpl*>(rfh)->GetAssociatedLocalFrame()) {
+ qWarning() << "Local frame is gone, not running script";
+ return 0;
+ }
content::RenderFrameHost::JavaScriptResultCallback callback = base::BindOnce(&callbackOnEvaluateJS, m_adapterClient, m_nextRequestId);
if (worldId == 0)
rfh->ExecuteJavaScript(toString16(javaScript), std::move(callback));
@@ -1243,7 +1261,10 @@ void WebContentsAdapter::openDevToolsFrontend(QSharedPointer<WebContentsAdapter>
setLifecycleState(LifecycleState::Active);
- m_devToolsFrontend = DevToolsFrontendQt::Show(frontendAdapter, m_webContents.get());
+ content::WebContents *webContents = m_webContents.get();
+ if (content::WebContents *guest = guestWebContents())
+ webContents = guest;
+ m_devToolsFrontend = DevToolsFrontendQt::Show(frontendAdapter, webContents);
updateRecommendedState();
}
@@ -1263,6 +1284,11 @@ void WebContentsAdapter::devToolsFrontendDestroyed(DevToolsFrontendQt *frontend)
updateRecommendedState();
}
+QString WebContentsAdapter::devToolsId()
+{
+ return QString::fromStdString(DevToolsFrontendQt::GetId(m_webContents.get()));
+}
+
void WebContentsAdapter::exitFullScreen()
{
CHECK_INITIALIZED();
@@ -1523,7 +1549,7 @@ void WebContentsAdapter::startDragging(QObject *dragSource, const content::DropD
}
{
- base::CurrentThread::ScopedNestableTaskAllower allow;
+ base::CurrentThread::ScopedAllowApplicationTasksInNativeNestedLoop allow;
drag->exec(allowedActions);
}
@@ -1593,7 +1619,7 @@ static void fillDropDataFromMimeData(content::DropData *dropData, const QMimeDat
}
if (!dropData->filenames.empty())
return;
- if (mimeData->hasUrls()) {
+ if (!urls.empty()) {
dropData->url = toGurl(urls.first());
if (mimeData->hasText())
dropData->url_title = toString16(mimeData->text());
@@ -1772,6 +1798,20 @@ void WebContentsAdapter::resetTouchSelectionController()
rwhv->resetTouchSelectionController();
}
+void WebContentsAdapter::changeTextDirection(bool leftToRight)
+{
+ CHECK_INITIALIZED();
+ if (auto rwhv = static_cast<RenderWidgetHostViewQt *>(m_webContents->GetRenderWidgetHostView())) {
+ auto textInputManager = rwhv->GetTextInputManager();
+ if (!textInputManager)
+ return;
+ if (auto activeWidget = textInputManager->GetActiveWidget()) {
+ activeWidget->UpdateTextDirection(leftToRight ? base::i18n::TextDirection::LEFT_TO_RIGHT : base::i18n::TextDirection::RIGHT_TO_LEFT);
+ activeWidget->NotifyTextDirection();
+ }
+ }
+}
+
WebContentsAdapterClient::RenderProcessTerminationStatus
WebContentsAdapterClient::renderProcessExitStatus(int terminationStatus) {
auto status = WebContentsAdapterClient::RenderProcessTerminationStatus(-1);
@@ -1927,7 +1967,7 @@ WebContentsAdapter::LifecycleState WebContentsAdapter::determineRecommendedState
// Do not discard PDFs as they might contain entry that is not saved and they
// don't remember their scrolling positions. See crbug.com/547286 and
// crbug.com/65244.
- if (m_webContents->GetContentsMimeType() == "application/pdf")
+ if (m_webContents->GetContentsMimeType() == kPDFMimeType)
return LifecycleState::Frozen;
return LifecycleState::Discarded;
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index 1f2f08d73..62c3f087c 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -60,7 +60,7 @@ class ProfileQt;
class WebEnginePageHost;
class WebChannelIPCTransportHost;
-class Q_WEBENGINECORE_PRIVATE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> {
+class Q_WEBENGINECORE_EXPORT WebContentsAdapter : public QEnableSharedFromThis<WebContentsAdapter> {
public:
static QSharedPointer<WebContentsAdapter> createFromSerializedNavigationHistory(QDataStream &input, WebContentsAdapterClient *adapterClient);
WebContentsAdapter();
@@ -159,6 +159,7 @@ public:
void openDevToolsFrontend(QSharedPointer<WebContentsAdapter> devtoolsFrontend);
void closeDevToolsFrontend();
void devToolsFrontendDestroyed(DevToolsFrontendQt *frontend);
+ QString devToolsId();
void grantMediaAccessPermission(const QUrl &securityOrigin, WebContentsAdapterClient::MediaRequestFlags flags);
void grantMouseLockPermission(const QUrl &securityOrigin, bool granted);
@@ -201,6 +202,7 @@ public:
bool hasFocusedFrame() const;
void resetSelection();
void resetTouchSelectionController();
+ void changeTextDirection(bool leftToRight);
// meant to be used within WebEngineCore only
void initialize(content::SiteInstance *site);
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index afbd2b5f2..1a1474644 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -36,6 +36,7 @@ QT_FORWARD_DECLARE_CLASS(QWebEngineUrlRequestInterceptor)
QT_FORWARD_DECLARE_CLASS(QWebEngineContextMenuRequest)
QT_FORWARD_DECLARE_CLASS(QWebEngineCertificateError)
QT_FORWARD_DECLARE_CLASS(QWebEngineSettings)
+QT_FORWARD_DECLARE_CLASS(QWebEngineWebAuthUxRequest)
namespace content {
struct DropData;
@@ -48,6 +49,7 @@ class CertificateErrorController;
class ClientCertSelectController;
class AuthenticationDialogController;
class ColorChooserController;
+class DesktopMediaController;
class FilePickerController;
class JavaScriptDialogController;
class RenderWidgetHostViewQt;
@@ -59,7 +61,7 @@ class WebContentsAdapter;
class WebContentsDelegateQt;
class WebEngineSettings;
-class Q_WEBENGINECORE_PRIVATE_EXPORT WebContentsAdapterClient {
+class Q_WEBENGINECORE_EXPORT WebContentsAdapterClient {
public:
// This must match window_open_disposition_list.h.
enum WindowOpenDisposition {
@@ -166,6 +168,7 @@ public:
virtual void close() = 0;
virtual void windowCloseRejected() = 0;
virtual void contextMenuRequested(QWebEngineContextMenuRequest *request) = 0;
+ virtual void desktopMediaRequested(DesktopMediaController *) = 0;
virtual void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame) = 0;
virtual void requestFullScreenMode(const QUrl &origin, bool fullscreen) = 0;
virtual bool isFullScreenMode() const = 0;
@@ -215,6 +218,7 @@ public:
virtual ProfileAdapter *profileAdapter() = 0;
virtual WebContentsAdapter* webContentsAdapter() = 0;
virtual void releaseProfile() = 0;
+ virtual void showWebAuthDialog(QWebEngineWebAuthUxRequest *request) = 0;
};
} // namespace QtWebEngineCore
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index b58b56500..194274fcb 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -12,10 +12,13 @@
#include "color_chooser_qt.h"
#include "custom_handlers/protocol_handler_registry_factory.h"
#include "custom_handlers/register_protocol_handler_request_controller_impl.h"
+#include "desktop_media_controller.h"
+#include "desktop_media_controller_p.h"
#include "file_picker_controller.h"
#include "find_text_helper.h"
#include "javascript_dialog_manager_qt.h"
#include "media_capture_devices_dispatcher.h"
+#include "native_web_keyboard_event_qt.h"
#include "profile_adapter.h"
#include "profile_qt.h"
#include "qwebengineloadinginfo.h"
@@ -244,9 +247,9 @@ void WebContentsDelegateQt::LoadProgressChanged(double progress)
bool WebContentsDelegateQt::HandleKeyboardEvent(content::WebContents *, const content::NativeWebKeyboardEvent &event)
{
- Q_ASSERT(!event.skip_in_browser);
+ Q_ASSERT(!event.skip_if_unhandled);
if (event.os_event)
- m_viewClient->unhandledKeyEvent(reinterpret_cast<QKeyEvent *>(event.os_event));
+ m_viewClient->unhandledKeyEvent(ToKeyEvent(event.os_event));
// FIXME: ?
return true;
}
@@ -311,6 +314,9 @@ void WebContentsDelegateQt::RenderViewHostChanged(content::RenderViewHost *, con
Q_ASSERT(rwhv->delegate());
rwhv->delegate()->adapterClientChanged(m_viewClient);
m_viewClient->zoomUpdateIsNeeded();
+ auto backgroundColor = m_viewClient->backgroundColor();
+ if (backgroundColor != Qt::white)
+ m_viewClient->webContentsAdapter()->setBackgroundColor(backgroundColor);
}
}
@@ -383,7 +389,8 @@ void WebContentsDelegateQt::emitLoadFinished(bool isErrorPage)
? QWebEngineLoadingInfo::LoadStoppedStatus : QWebEngineLoadingInfo::LoadFailedStatus);
QWebEngineLoadingInfo info(m_loadingInfo.url, loadStatus, m_loadingInfo.isErrorPage,
m_loadingInfo.errorDescription, m_loadingInfo.errorCode,
- QWebEngineLoadingInfo::ErrorDomain(m_loadingInfo.errorDomain));
+ QWebEngineLoadingInfo::ErrorDomain(m_loadingInfo.errorDomain),
+ m_loadingInfo.responseHeaders);
m_viewClient->loadFinished(std::move(info));
m_viewClient->updateNavigationActions();
}
@@ -411,6 +418,20 @@ void WebContentsDelegateQt::DidFinishNavigation(content::NavigationHandle *navig
emitLoadCommitted();
}
+ const net::HttpResponseHeaders * const responseHeaders = navigation_handle->GetResponseHeaders();
+ if (responseHeaders != nullptr) {
+ m_loadingInfo.responseHeaders.clear();
+ std::size_t iter = 0;
+ std::string headerName;
+ std::string headerValue;
+ while (responseHeaders->EnumerateHeaderLines(&iter, &headerName, &headerValue)) {
+ m_loadingInfo.responseHeaders.insert(
+ QByteArray::fromStdString(headerName),
+ QByteArray::fromStdString(headerValue)
+ );
+ }
+ }
+
// Success is reported by DidFinishLoad, but DidFailLoad is now dead code and needs to be handled below
if (navigation_handle->GetNetErrorCode() == net::OK)
return;
@@ -600,9 +621,45 @@ void WebContentsDelegateQt::FindReply(content::WebContents *source, int request_
m_findTextHelper->handleFindReply(source, request_id, number_of_matches, selection_rect, active_match_ordinal, final_update);
}
+static void processMediaAccessRequest(content::WebContents *webContents,
+ const content::MediaStreamRequest &request,
+ content::MediaResponseCallback callback,
+ content::DesktopMediaID id)
+{
+ MediaCaptureDevicesDispatcher::GetInstance()->processMediaAccessRequest(
+ webContents, request, std::move(callback), id);
+}
+
+static inline bool needsPickerDialog(const content::MediaStreamRequest &request)
+{
+ return (request.requested_video_device_id.empty() && // device already selected in chooseDesktopMedia
+ (request.video_type == blink::mojom::MediaStreamType::GUM_DESKTOP_VIDEO_CAPTURE
+ || request.video_type == blink::mojom::MediaStreamType::DISPLAY_VIDEO_CAPTURE));
+}
+
void WebContentsDelegateQt::RequestMediaAccessPermission(content::WebContents *web_contents, const content::MediaStreamRequest &request, content::MediaResponseCallback callback)
{
- MediaCaptureDevicesDispatcher::GetInstance()->processMediaAccessRequest(web_contents, request, std::move(callback));
+ if (needsPickerDialog(request)) {
+#if QT_CONFIG(webengine_webrtc)
+ base::OnceCallback<void(content::DesktopMediaID)> cb = base::BindOnce(
+ &processMediaAccessRequest, web_contents, std::move(request), std::move(callback));
+ // ownership is taken by the request
+ auto *controller = new DesktopMediaController(
+ new DesktopMediaControllerPrivate(std::move(cb)));
+ QObject::connect(controller, &DesktopMediaController::mediaListsInitialized, [controller, delegate = AsWeakPtr()]() {
+ if (delegate)
+ delegate->adapterClient()->desktopMediaRequested(controller);
+ else
+ controller->deleteLater();
+ });
+#else
+ // To keep the old behavior return the default screen even if webrtc is disabled
+ processMediaAccessRequest(web_contents, std::move(request), std::move(callback),
+ content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, 0));
+#endif // QT_CONFIG(webengine_webrtc)
+ } else {
+ processMediaAccessRequest(web_contents, std::move(request), std::move(callback), {});
+ }
}
void WebContentsDelegateQt::SetContentsBounds(content::WebContents *source, const gfx::Rect &bounds)
@@ -625,12 +682,6 @@ void WebContentsDelegateQt::UpdateTargetURL(content::WebContents* source, const
m_viewClient->didUpdateTargetURL(toQt(url));
}
-void WebContentsDelegateQt::OnVisibilityChanged(content::Visibility visibility)
-{
- if (visibility != content::Visibility::HIDDEN)
- web_cache::WebCacheManager::GetInstance()->ObserveActivity(web_contents()->GetPrimaryMainFrame()->GetProcess()->GetID());
-}
-
void WebContentsDelegateQt::ActivateContents(content::WebContents* contents)
{
QWebEngineSettings *settings = m_viewClient->webEngineSettings();
@@ -735,12 +786,6 @@ void WebContentsDelegateQt::BeforeUnloadFired(content::WebContents *tab, bool pr
m_viewClient->windowCloseRejected();
}
-void WebContentsDelegateQt::BeforeUnloadFired(bool proceed, const base::TimeTicks &proceed_time)
-{
- Q_UNUSED(proceed);
- Q_UNUSED(proceed_time);
-}
-
bool WebContentsDelegateQt::CheckMediaAccessPermission(content::RenderFrameHost *, const GURL& security_origin, blink::mojom::MediaStreamType type)
{
switch (type) {
@@ -811,6 +856,15 @@ void WebContentsDelegateQt::ResourceLoadComplete(content::RenderFrameHost* rende
}
}
+void WebContentsDelegateQt::InnerWebContentsAttached(content::WebContents *inner_web_contents,
+ content::RenderFrameHost *render_frame_host,
+ bool is_full_page)
+{
+ blink::web_pref::WebPreferences guestPrefs = inner_web_contents->GetOrCreateWebPreferences();
+ webEngineSettings()->overrideWebPreferences(inner_web_contents, &guestPrefs);
+ inner_web_contents->SetWebPreferences(guestPrefs);
+}
+
FindTextHelper *WebContentsDelegateQt::findTextHelper()
{
return m_findTextHelper.data();
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index eda4e1e57..51004878d 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -12,6 +12,7 @@
#include "web_contents_adapter_client.h"
#include <QtCore/qlist.h>
+#include <QtCore/qmap.h>
namespace blink {
namespace web_pref {
@@ -123,12 +124,13 @@ public:
void DidStopLoading() override;
void DidFailLoad(content::RenderFrameHost* render_frame_host, const GURL& validated_url, int error_code) override;
void DidFinishLoad(content::RenderFrameHost *render_frame_host, const GURL &validated_url) override;
- void BeforeUnloadFired(bool proceed, const base::TimeTicks& proceed_time) override;
- void OnVisibilityChanged(content::Visibility visibility) override;
void ActivateContents(content::WebContents* contents) override;
void ResourceLoadComplete(content::RenderFrameHost* render_frame_host,
const content::GlobalRequestID& request_id,
const blink::mojom::ResourceLoadInfo& resource_load_info) override;
+ void InnerWebContentsAttached(content::WebContents *inner_web_contents,
+ content::RenderFrameHost *render_frame_host,
+ bool is_full_page) override;
void didFailLoad(const QUrl &url, int errorCode, const QString &errorDescription);
void overrideWebPreferences(content::WebContents *, blink::web_pref::WebPreferences*);
@@ -138,8 +140,8 @@ public:
void launchExternalURL(const QUrl &url, ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture);
FindTextHelper *findTextHelper();
- void setSavePageInfo(const SavePageInfo &spi) { m_savePageInfo = spi; }
- const SavePageInfo &savePageInfo() { return m_savePageInfo; }
+ void setSavePageInfo(SavePageInfo *spi) { m_savePageInfo.reset(spi); }
+ SavePageInfo *savePageInfo() { return m_savePageInfo.get(); }
WebEngineSettings *webEngineSettings() const;
WebContentsAdapter *webContentsAdapter() const;
@@ -179,7 +181,7 @@ private:
WebContentsAdapterClient *m_viewClient;
QScopedPointer<FindTextHelper> m_findTextHelper;
- SavePageInfo m_savePageInfo;
+ std::unique_ptr<SavePageInfo> m_savePageInfo;
QSharedPointer<FilePickerController> m_filePickerController;
LoadingState m_loadingState;
FrameFocusedObserver m_frameFocusedObserver;
@@ -200,6 +202,7 @@ private:
int errorCode = 0, errorDomain = 0;
QString errorDescription;
bool triggersErrorPage = false;
+ QMultiMap<QByteArray, QByteArray> responseHeaders;
void clear() { *this = LoadingInfo(); }
} m_loadingInfo;
diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h
index 15528b41d..8754250e6 100644
--- a/src/core/web_contents_view_qt.h
+++ b/src/core/web_contents_view_qt.h
@@ -73,6 +73,7 @@ public:
void FocusThroughTabTraversal(bool reverse) override;
void OnCapturerCountChanged() override { QT_NOT_YET_IMPLEMENTED }
void FullscreenStateChanged(bool) override { }
+ void UpdateWindowControlsOverlay(const gfx::Rect &) override { QT_NOT_YET_IMPLEMENTED }
#if BUILDFLAG(IS_MAC)
bool CloseTabAfterEventTrackingIfNeeded() override { QT_NOT_YET_IMPLEMENTED return false; }
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp
index 50dcde636..94110d51c 100644
--- a/src/core/web_engine_context.cpp
+++ b/src/core/web_engine_context.cpp
@@ -4,9 +4,10 @@
#include "web_engine_context.h"
#include <math.h>
+#include <QtGui/private/qrhi_p.h>
#include "base/base_switches.h"
-#include "base/bind.h"
+#include "base/functional/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
#include "base/power_monitor/power_monitor.h"
@@ -21,6 +22,7 @@
#include "chrome/browser/media/webrtc/webrtc_log_uploader.h"
#endif
#include "chrome/common/chrome_switches.h"
+#include "content/common/process_visibility_tracker.h"
#include "content/gpu/gpu_child_thread.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/compositor/viz_process_transport_factory.h"
@@ -34,9 +36,13 @@
#include "components/web_cache/browser/web_cache_manager.h"
#include "content/app/mojo_ipc_support.h"
#include "content/browser/devtools/devtools_http_handler.h"
+#include "content/browser/gpu/gpu_main_thread_factory.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
#include "content/browser/scheduler/browser_task_executor.h"
#include "content/browser/startup_data_impl.h"
#include "content/browser/startup_helper.h"
+#include "content/browser/utility_process_host.h"
+#include "content/gpu/in_process_gpu_thread.h"
#include "content/public/app/content_main.h"
#include "content/public/app/content_main_runner.h"
#include "content/public/browser/browser_main_runner.h"
@@ -51,9 +57,9 @@
#include "content/public/common/content_paths.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
-#include "content/public/common/network_service_util.h"
+#include "content/renderer/in_process_renderer_thread.h"
+#include "content/utility/in_process_utility_thread.h"
#include "gpu/command_buffer/service/gpu_switches.h"
-#include "gpu/command_buffer/service/sync_point_manager.h"
#include "gpu/config/gpu_finch_features.h"
#include "media/audio/audio_manager.h"
#include "media/base/media_switches.h"
@@ -69,6 +75,7 @@
#include "ui/base/ui_base_features.h"
#include "ui/events/event_switches.h"
#include "ui/native_theme/native_theme_features.h"
+#include "ui/gl/gl_utils.h"
#include "ui/gl/gl_switches.h"
#if defined(Q_OS_WIN)
#include "sandbox/win/src/sandbox_types.h"
@@ -76,7 +83,7 @@
#endif // Q_OS_WIN
#if defined(Q_OS_MACOS)
-#include "base/mac/foundation_util.h"
+#include "base/apple/foundation_util.h"
#endif
#if QT_CONFIG(accessibility)
@@ -103,6 +110,7 @@
#include <qopenglcontext_platform.h>
#endif
#include <QQuickWindow>
+#include <QRegularExpression>
#include <QStringList>
#include <QSurfaceFormat>
#include <QNetworkProxy>
@@ -117,16 +125,19 @@ Q_GUI_EXPORT QOpenGLContext *qt_gl_global_share_context();
QT_END_NAMESPACE
#endif
+#define STRINGIFY_LITERAL(x) #x
+#define STRINGIFY_EXPANDED(x) STRINGIFY_LITERAL(x)
+
namespace QtWebEngineCore {
Q_LOGGING_CATEGORY(webEngineContextLog, "qt.webenginecontext")
-#if QT_CONFIG(opengl)
-
static bool usingSupportedSGBackend()
{
if (QQuickWindow::graphicsApi() != QSGRendererInterface::OpenGL
- && QQuickWindow::graphicsApi() != QSGRendererInterface::Vulkan)
+ && QQuickWindow::graphicsApi() != QSGRendererInterface::Vulkan
+ && QQuickWindow::graphicsApi() != QSGRendererInterface::Metal
+ && QQuickWindow::graphicsApi() != QSGRendererInterface::Direct3D11)
return false;
const QStringList args = QGuiApplication::arguments();
@@ -149,6 +160,7 @@ static bool usingSupportedSGBackend()
return device.isEmpty() || device == QLatin1String("rhi");
}
+#if QT_CONFIG(opengl)
bool usingSoftwareDynamicGL()
{
const char openGlVar[] = "QT_OPENGL";
@@ -177,19 +189,27 @@ static bool openGLPlatformSupport()
QPlatformIntegration::OpenGL);
}
-static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
+static std::string getGLType(bool enableGLSoftwareRendering, bool disableGpu)
{
- const char *glType = gl::kGLImplementationDisabledName;
const bool tryGL =
usingSupportedSGBackend() && !usingSoftwareDynamicGL() && openGLPlatformSupport();
-
if (disableGpu || (!tryGL && !enableGLSoftwareRendering))
- return glType;
+ return gl::kGLImplementationDisabledName;
+
+#if defined(Q_OS_MACOS)
+ return gl::kGLImplementationANGLEName;
+#else
+#if defined(Q_OS_WIN)
+ if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11
+ || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) {
+ return gl::kGLImplementationANGLEName;
+ }
+#endif
if (!qt_gl_global_share_context() || !qt_gl_global_share_context()->isValid()) {
- qWarning("WebEngineContext used before QtWebEngineCore::initialize() or OpenGL context "
+ qWarning("WebEngineContext is used before QtWebEngineQuick::initialize() or OpenGL context "
"creation failed.");
- return glType;
+ return gl::kGLImplementationDisabledName;
}
const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format();
@@ -197,22 +217,13 @@ static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
switch (sharedFormat.renderableType()) {
case QSurfaceFormat::OpenGL:
if (sharedFormat.profile() == QSurfaceFormat::CoreProfile) {
-#if defined(Q_OS_MACOS)
- // Chromium supports core profile only on mac
- glType = gl::kGLImplementationCoreProfileName;
-#else
- glType = gl::kGLImplementationDesktopName;
qWarning("An OpenGL Core Profile was requested, but it is not supported "
"on the current platform. Falling back to a non-Core profile. "
"Note that this might cause rendering issues.");
-#endif
- } else {
- glType = gl::kGLImplementationDesktopName;
}
- break;
+ return gl::kGLImplementationDesktopName;
case QSurfaceFormat::OpenGLES:
- glType = gl::kGLImplementationEGLName;
- break;
+ return gl::kGLImplementationEGLName;
case QSurfaceFormat::OpenVG:
case QSurfaceFormat::DefaultRenderableType:
default:
@@ -220,53 +231,180 @@ static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
qWarning("Unsupported rendering surface format. Please open bug report at "
"https://bugreports.qt.io");
}
- return glType;
+
+ return gl::kGLImplementationDisabledName;
+#endif // defined(Q_OS_MACOS)
}
#else
-static const char *getGLType(bool enableGLSoftwareRendering, bool disableGpu)
+static std::string getGLType(bool /*enableGLSoftwareRendering*/, bool disableGpu)
{
+ if (disableGpu)
+ return gl::kGLImplementationDisabledName;
+#if defined(Q_OS_MACOS)
+ return gl::kGLImplementationANGLEName;
+#elif defined(Q_OS_WIN)
+ if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11
+ || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) {
+ return gl::kGLImplementationANGLEName;
+ }
+#endif
return gl::kGLImplementationDisabledName;
}
#endif // QT_CONFIG(opengl)
+static std::string getVulkanType(base::CommandLine *cmd)
+{
+#if QT_CONFIG(webengine_vulkan)
+ if (cmd->HasSwitch(switches::kUseVulkan))
+ return cmd->GetSwitchValueASCII(switches::kUseVulkan);
+#endif
+
+ return "disabled";
+}
+
+static std::string getAngleType(const std::string &glType, base::CommandLine *cmd)
+{
+ if (glType == gl::kGLImplementationANGLEName) {
+ if (cmd->HasSwitch(switches::kUseANGLE))
+ return cmd->GetSwitchValueASCII(switches::kUseANGLE);
+
+#if defined(Q_OS_WIN)
+ return gl::kANGLEImplementationD3D11Name;
+#elif defined(Q_OS_MACOS)
+ return gl::kANGLEImplementationMetalName;
+#else
+ return gl::kANGLEImplementationDefaultName;
+#endif
+ }
+
+ return "disabled";
+}
+
+static quint64 getGPUVendorId()
+{
+#if QT_CONFIG(webengine_vulkan)
+ QVulkanInstance vulkanInstance;
+ vulkanInstance.setApiVersion(QVersionNumber(1, 1));
+ if (vulkanInstance.create()) {
+ QRhiVulkanInitParams params;
+ params.inst = &vulkanInstance;
+ QScopedPointer<QRhi> rhi(QRhi::create(QRhi::Vulkan, &params, QRhi::Flags(), nullptr));
+ return rhi->driverInfo().vendorId;
+ }
+#endif
+
+ return 0;
+}
+
+#if defined(Q_OS_WIN)
+static QString getAdapterLuid() {
+ static const bool preferSoftwareDevice = qEnvironmentVariableIntValue("QSG_RHI_PREFER_SOFTWARE_RENDERER");
+ QRhiD3D11InitParams rhiParams;
+ QRhi::Flags flags;
+ if (preferSoftwareDevice) {
+ flags |= QRhi::PreferSoftwareRenderer;
+ }
+ QScopedPointer<QRhi> rhi(QRhi::create(QRhi::D3D11,&rhiParams,flags,nullptr));
+ // mimic what QSGRhiSupport and QBackingStoreRhi does
+ if (!rhi && !preferSoftwareDevice) {
+ flags |= QRhi::PreferSoftwareRenderer;
+ rhi.reset(QRhi::create(QRhi::D3D11, &rhiParams, flags));
+ }
+ if (rhi) {
+ const QRhiD3D11NativeHandles *handles =
+ static_cast<const QRhiD3D11NativeHandles *>(rhi->nativeHandles());
+ Q_ASSERT(handles);
+ return QString("%1,%2").arg(handles->adapterLuidHigh).arg(handles->adapterLuidLow);
+ } else {
+ return QString();
+ }
+}
+#endif
+
#if QT_CONFIG(webengine_pepper_plugins)
void dummyGetPluginCallback(const std::vector<content::WebPluginInfo>&)
{
}
#endif
-static void logContext(const char *glType, base::CommandLine *cmd)
+static void logContext(const std::string &glType, base::CommandLine *cmd)
{
if (Q_UNLIKELY(webEngineContextLog().isDebugEnabled())) {
+ QStringList log;
+ log << "\n";
+
+ log << "Chromium GL Backend:" << glType.c_str() << "\n";
+ log << "Chromium ANGLE Backend:" << getAngleType(glType, cmd).c_str() << "\n";
+ log << "Chromium Vulkan Backend:" << getVulkanType(cmd).c_str() << "\n";
+ log << "\n";
+
+ log << "QSG RHI Backend:" << QSGRhiSupport::instance()->rhiBackendName() << "\n";
+ log << "QSG RHI Backend Supported:" << (usingSupportedSGBackend() ? "yes" : "no") << "\n";
+ log << "GPU Vendor:";
+ if (quint64 vendorId = getGPUVendorId()) {
+ switch (vendorId) {
+ case 0x1002:
+ log << "AMD";
+ break;
+ case 0x10DE:
+ log << "NVIDIA";
+ break;
+ case 0x8086:
+ log << "Intel";
+ break;
+ case 0x1010:
+ log << "ImgTec";
+ break;
+ case 0x13B5:
+ log << "ARM";
+ break;
+ case 0x5143:
+ log << "Qualcomm";
+ break;
+ default:
+ break;
+ }
+ log << QString("(0x%1)\n").arg(vendorId, 0, 16);
+ } else {
+ log << "Unable to detect\n";
+ }
+ log << "\n";
+
#if QT_CONFIG(opengl)
- const QSurfaceFormat sharedFormat = qt_gl_global_share_context()->format();
- const auto profile = QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey(
- sharedFormat.profile());
- const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey(
- sharedFormat.renderableType());
- const base::CommandLine::SwitchMap switch_map = cmd->GetSwitches();
- QStringList params;
- for (const auto &pair : switch_map)
- params << " * " << toQt(pair.first)
- << toQt(pair.second) << "\n";
- qCDebug(webEngineContextLog,
- "\n\nGL Type: %s\n"
- "Surface Type: %s\n"
- "Surface Profile: %s\n"
- "Surface Version: %d.%d\n"
- "QSG RHI Backend: %s\n"
- "Using Supported QSG Backend: %s\n"
- "Using Software Dynamic GL: %s\n"
- "Using Multithreaded OpenGL: %s\n\n"
- "Init Parameters:\n %s",
- glType, type, profile, sharedFormat.majorVersion(), sharedFormat.minorVersion(),
- qUtf8Printable(QSGRhiSupport::instance()->rhiBackendName()),
- usingSupportedSGBackend() ? "yes" : "no", usingSoftwareDynamicGL() ? "yes" : "no",
- !WebEngineContext::isGpuServiceOnUIThread() ? "yes" : "no",
- qPrintable(params.join(" ")));
-#else
- qCDebug(webEngineContextLog) << "WebEngine compiled with no opengl enabled.";
-#endif //QT_CONFIG(opengl)
+#if defined(USE_OZONE)
+ log << "Using GLX:" << (GLContextHelper::getGlxPlatformInterface() ? "yes" : "no") << "\n";
+ log << "Using EGL:" << (GLContextHelper::getEglPlatformInterface() ? "yes" : "no") << "\n";
+#endif
+ log << "Using Shared GL:" << (qt_gl_global_share_context() ? "yes" : "no") << "\n";
+ if (qt_gl_global_share_context()) {
+ log << "Using Software Dynamic GL:" << (usingSoftwareDynamicGL() ? "yes" : "no")
+ << "\n";
+
+ const QSurfaceFormat sharedFormat = qt_gl_global_share_context()
+ ? qt_gl_global_share_context()->format()
+ : QSurfaceFormat::defaultFormat();
+ const auto profile =
+ QMetaEnum::fromType<QSurfaceFormat::OpenGLContextProfile>().valueToKey(
+ sharedFormat.profile());
+ const auto type = QMetaEnum::fromType<QSurfaceFormat::RenderableType>().valueToKey(
+ sharedFormat.renderableType());
+ log << "Surface Type:" << type << "\n";
+ log << "Surface Profile:" << profile << "\n";
+ log << "Surface Version:"
+ << QString("%1.%2")
+ .arg(sharedFormat.majorVersion())
+ .arg(sharedFormat.minorVersion())
+ << "\n";
+ }
+ log << "\n";
+#endif // QT_CONFIG(opengl)
+
+ log << "Init Parameters:\n";
+ const base::CommandLine::SwitchMap switchMap = cmd->GetSwitches();
+ for (const auto &pair : switchMap)
+ log << " * " << toQt(pair.first) << toQt(pair.second) << "\n";
+
+ qCDebug(webEngineContextLog) << qPrintable(log.join(" "));
}
}
@@ -413,7 +551,6 @@ void WebEngineContext::destroy()
// on IO thread (triggered by ~BrowserMainRunner). But by that time the UI
// task runner is not working anymore so we need to do this earlier.
cleanupVizProcess();
- destroyGpuProcess();
// Flush the UI message loop before quitting.
flushMessages();
@@ -470,7 +607,6 @@ WebEngineContext::~WebEngineContext()
Q_ASSERT(!m_devtoolsServer);
Q_ASSERT(!m_browserRunner);
Q_ASSERT(m_profileAdapters.isEmpty());
- delete s_syncPointManager.fetchAndStoreRelaxed(nullptr);
}
WebEngineContext *WebEngineContext::current()
@@ -544,18 +680,6 @@ ProxyAuthentication WebEngineContext::qProxyNetworkAuthentication(QString host,
const static char kChromiumFlagsEnv[] = "QTWEBENGINE_CHROMIUM_FLAGS";
const static char kDisableSandboxEnv[] = "QTWEBENGINE_DISABLE_SANDBOX";
-const static char kDisableInProcGpuThread[] = "QTWEBENGINE_DISABLE_GPU_THREAD";
-
-// static
-bool WebEngineContext::isGpuServiceOnUIThread()
-{
- static bool threadedGpu =
-#if QT_CONFIG(opengl) && !defined(Q_OS_MACOS)
- QOpenGLContext::supportsThreadedOpenGL() &&
-#endif
- !qEnvironmentVariableIsSet(kDisableInProcGpuThread);
- return !threadedGpu;
-}
static void initializeFeatureList(base::CommandLine *commandLine, std::vector<std::string> enableFeatures, std::vector<std::string> disableFeatures)
{
@@ -607,7 +731,7 @@ WebEngineContext::WebEngineContext()
#if defined(Q_OS_MACOS)
// The bundled handling is currently both completely broken in Chromium,
// and unnecessary for us.
- base::mac::SetOverrideAmIBundled(false);
+ base::apple::SetOverrideAmIBundled(false);
#endif
base::ThreadPoolInstance::Create("Browser");
@@ -654,8 +778,6 @@ WebEngineContext::WebEngineContext()
qInfo() << "Sandboxing disabled by user.";
}
- parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing);
-
// Do not advertise a feature we have removed at compile time
parsedCommandLine->AppendSwitch(switches::kDisableSpeechAPI);
@@ -671,12 +793,16 @@ WebEngineContext::WebEngineContext()
// Avoid crashing when websites tries using this feature (since 83)
disableFeatures.push_back(features::kInstalledApp.name);
+ // Not implemented but it overrides the devtools eyedropper
+ // Should be sync with kEyeDropper base::Feature
+ parsedCommandLine->AppendSwitchASCII(switches::kDisableBlinkFeatures, "EyeDropperAPI");
+ disableFeatures.push_back(features::kEyeDropper.name);
+
// Explicitly tell Chromium about default-on features we do not support
disableFeatures.push_back(features::kBackgroundFetch.name);
disableFeatures.push_back(features::kWebOTP.name);
disableFeatures.push_back(features::kWebPayments.name);
disableFeatures.push_back(features::kWebUsb.name);
- disableFeatures.push_back(media::kPictureInPicture.name);
if (useEmbeddedSwitches) {
// embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc
@@ -685,11 +811,41 @@ WebEngineContext::WebEngineContext()
parsedCommandLine->AppendSwitch(cc::switches::kDisableCompositedAntialiasing);
}
-#if QT_CONFIG(webengine_vulkan)
+#if QT_CONFIG(webengine_vulkan) && defined(USE_OZONE)
if (QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) {
enableFeatures.push_back(features::kVulkan.name);
parsedCommandLine->AppendSwitchASCII(switches::kUseVulkan,
switches::kVulkanImplementationNameNative);
+ const char deviceExtensionsVar[] = "QT_VULKAN_DEVICE_EXTENSIONS";
+ QByteArrayList requiredDeviceExtensions = { "VK_KHR_external_memory_fd",
+ "VK_EXT_external_memory_dma_buf",
+ "VK_EXT_image_drm_format_modifier" };
+ if (qEnvironmentVariableIsSet(deviceExtensionsVar)) {
+ QByteArrayList envExtList = qgetenv(deviceExtensionsVar).split(';');
+ int found = 0;
+ for (const QByteArray &ext : requiredDeviceExtensions) {
+ if (envExtList.contains(ext))
+ found++;
+ }
+ if (found != requiredDeviceExtensions.size()) {
+ qWarning().nospace()
+ << "Vulkan rendering may fail because " << deviceExtensionsVar
+ << " environment variable is already set but it doesn't contain"
+ << " some of the required Vulkan device extensions:\n"
+ << qPrintable(requiredDeviceExtensions.join('\n'));
+ }
+ } else {
+ qputenv(deviceExtensionsVar, requiredDeviceExtensions.join(';'));
+ }
+ }
+#endif // QT_CONFIG(webengine_vulkan) && defined(USE_OZONE)
+
+#if defined(Q_OS_WIN)
+ if (QQuickWindow::graphicsApi() == QSGRendererInterface::Direct3D11
+ || QQuickWindow::graphicsApi() == QSGRendererInterface::Vulkan) {
+ const QString luid = getAdapterLuid();
+ if (!luid.isEmpty())
+ parsedCommandLine->AppendSwitchASCII(switches::kUseAdapterLuid, luid.toStdString());
}
#endif
@@ -702,9 +858,14 @@ WebEngineContext::WebEngineContext()
// performant, but at least provides WebGL support.
// TODO(miklocek), check if this still works with latest chromium
const bool disableGpu = parsedCommandLine->HasSwitch(switches::kDisableGpu);
- const char *glType = getGLType(enableGLSoftwareRendering, disableGpu);
+ std::string glType;
+ if (parsedCommandLine->HasSwitch(switches::kUseGL))
+ glType = parsedCommandLine->GetSwitchValueASCII(switches::kUseGL);
+ else {
+ glType = getGLType(enableGLSoftwareRendering, disableGpu);
+ parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType);
+ }
- parsedCommandLine->AppendSwitchASCII(switches::kUseGL, glType);
parsedCommandLine->AppendSwitch(switches::kInProcessGPU);
if (glType != gl::kGLImplementationDisabledName) {
@@ -713,19 +874,26 @@ WebEngineContext::WebEngineContext()
parsedCommandLine->AppendSwitch(switches::kIgnoreGpuBlocklist);
}
#if QT_CONFIG(opengl)
- const QSurfaceFormat sharedFormat = QOpenGLContext::globalShareContext()->format();
- if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile)
- parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext);
+ if (glType != gl::kGLImplementationANGLEName) {
+ QOpenGLContext *shareContext = QOpenGLContext::globalShareContext();
+ Q_ASSERT(shareContext);
+ const QSurfaceFormat sharedFormat = shareContext->format();
+ if (sharedFormat.profile() == QSurfaceFormat::CompatibilityProfile)
+ parsedCommandLine->AppendSwitch(switches::kCreateDefaultGLContext);
#if defined(Q_OS_WIN)
- // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create
- // an OpenGL Core Profile context. If the switch is not set, it would always try to create a
- // Core Profile context, even if Qt uses a legacy profile, which causes
- // "Could not share GL contexts" warnings, because it's not possible to share between Core and
- // legacy profiles. See GLContextWGL::Initialize().
- if (sharedFormat.renderableType() == QSurfaceFormat::OpenGL
- && sharedFormat.profile() != QSurfaceFormat::CoreProfile)
- parsedCommandLine->AppendSwitch(switches::kDisableES3GLContext);
+ // This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create
+ // an OpenGL Core Profile context. If the switch is not set, it would always try to create a
+ // Core Profile context, even if Qt uses a legacy profile, which causes
+ // "Could not share GL contexts" warnings, because it's not possible to share between Core and
+ // legacy profiles. See GLContextWGL::Initialize().
+ if (sharedFormat.renderableType() == QSurfaceFormat::OpenGL
+ && sharedFormat.profile() != QSurfaceFormat::CoreProfile) {
+ gl::GlWorkarounds workarounds = gl::GetGlWorkarounds();
+ workarounds.disable_es3gl_context = true;
+ gl::SetGlWorkarounds(workarounds);
+ }
#endif
+ }
#endif //QT_CONFIG(opengl)
} else if (!disableGpu) {
parsedCommandLine->AppendSwitch(switches::kDisableGpu);
@@ -759,8 +927,9 @@ WebEngineContext::WebEngineContext()
content::StartBrowserThreadPool();
content::BrowserTaskExecutor::PostFeatureListSetup();
tracing::InitTracingPostThreadPoolStartAndFeatureList(false);
- m_discardableSharedMemoryManager = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
base::PowerMonitor::Initialize(std::make_unique<base::PowerMonitorDeviceSource>());
+ content::ProcessVisibilityTracker::GetInstance();
+ m_discardableSharedMemoryManager = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
m_mojoIpcSupport = std::make_unique<content::MojoIpcSupport>(content::BrowserTaskExecutor::CreateIOThread());
download::SetIOTaskRunner(m_mojoIpcSupport->io_thread()->task_runner());
@@ -826,19 +995,6 @@ WebRtcLogUploader *WebEngineContext::webRtcLogUploader()
#endif
-static QMutex s_spmMutex;
-QAtomicPointer<gpu::SyncPointManager> WebEngineContext::s_syncPointManager;
-
-gpu::SyncPointManager *WebEngineContext::syncPointManager()
-{
- if (gpu::SyncPointManager *spm = s_syncPointManager.loadAcquire())
- return spm;
- QMutexLocker lock(&s_spmMutex);
- if (!s_syncPointManager)
- s_syncPointManager.storeRelaxed(new gpu::SyncPointManager());
- return s_syncPointManager.loadRelaxed();
-}
-
base::CommandLine *WebEngineContext::initCommandLine(bool &useEmbeddedSwitches,
bool &enableGLSoftwareRendering)
{
@@ -852,11 +1008,14 @@ base::CommandLine *WebEngineContext::initCommandLine(bool &useEmbeddedSwitches,
}
base::CommandLine *parsedCommandLine = base::CommandLine::ForCurrentProcess();
+ int index = appArgs.indexOf(QRegularExpression(QLatin1String("--webEngineArgs"),
+ QRegularExpression::CaseInsensitiveOption));
if (qEnvironmentVariableIsSet(kChromiumFlagsEnv)) {
appArgs = appArgs.mid(0, 1); // Take application name and drop the rest
appArgs.append(parseEnvCommandLine(qEnvironmentVariable(kChromiumFlagsEnv)));
+ if (index > -1)
+ qWarning("Note 'webEngineArgs' are overridden by QTWEBENGINE_CHROMIUM_FLAGS");
} else {
- int index = appArgs.indexOf(QLatin1String("--webEngineArgs"));
if (index > -1) {
appArgs.erase(appArgs.begin() + 1, appArgs.begin() + index + 1);
} else {
@@ -873,6 +1032,22 @@ base::CommandLine *WebEngineContext::initCommandLine(bool &useEmbeddedSwitches,
appArgs.removeAll(QStringLiteral("--disable-embedded-switches"));
appArgs.removeAll(QStringLiteral("--enable-embedded-switches"));
+ bool isRemoteDebugPort =
+ (-1
+ != appArgs.indexOf(QRegularExpression(QStringLiteral("--remote-debugging-port=.*"),
+ QRegularExpression::CaseInsensitiveOption)))
+ || !qEnvironmentVariable("QTWEBENGINE_REMOTE_DEBUGGING").isEmpty();
+ bool isRemoteAllowOrigins =
+ (-1
+ != appArgs.indexOf(QRegularExpression(QStringLiteral("--remote-allow-origins=.*"),
+ QRegularExpression::CaseInsensitiveOption)));
+
+ if (isRemoteDebugPort && !isRemoteAllowOrigins) {
+ appArgs.append(QStringLiteral("--remote-allow-origins=*"));
+ qWarning("Added {--remote-allow-origins=*} to command-line arguments "
+ "to avoid web socket connection errors during remote debugging.");
+ }
+
base::CommandLine::StringVector argv;
argv.resize(appArgs.size());
#if defined(Q_OS_WIN)
@@ -892,21 +1067,34 @@ bool WebEngineContext::closingDown()
return m_closingDown;
}
+void WebEngineContext::registerMainThreadFactories()
+{
+ content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread);
+ content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread);
+ content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread);
+}
+
} // namespace
QT_BEGIN_NAMESPACE
const char *qWebEngineVersion() noexcept
{
- return QTWEBENGINECORE_VERSION_STR;
+ return STRINGIFY_EXPANDED(QTWEBENGINECORE_VERSION_STR);
+}
+
+const char *qWebEngineProcessName() noexcept
+{
+ return STRINGIFY_EXPANDED(QTWEBENGINEPROCESS_NAME);
}
const char *qWebEngineChromiumVersion() noexcept
{
- return CHROMIUM_VERSION;
+ return STRINGIFY_EXPANDED(CHROMIUM_VERSION);
}
+
const char *qWebEngineChromiumSecurityPatchVersion() noexcept
{
- return "108.0.5359.181"; // FIXME: Remember to update
+ return "122.0.6261.128"; // FIXME: Remember to update
}
QT_END_NAMESPACE
diff --git a/src/core/web_engine_context.h b/src/core/web_engine_context.h
index 6819d06f0..50b080db1 100644
--- a/src/core/web_engine_context.h
+++ b/src/core/web_engine_context.h
@@ -32,7 +32,6 @@ class DiscardableSharedMemoryManager;
namespace gpu {
struct GpuPreferences;
-class SyncPointManager;
}
#if QT_CONFIG(webengine_printing_and_pdf)
@@ -85,10 +84,6 @@ public:
static base::CommandLine *initCommandLine(bool &useEmbeddedSwitches,
bool &enableGLSoftwareRendering);
- static gpu::SyncPointManager *syncPointManager();
-
- static bool isGpuServiceOnUIThread();
-
private:
friend class base::RefCounted<WebEngineContext>;
friend class ProfileAdapter;
@@ -96,7 +91,6 @@ private:
~WebEngineContext();
static void registerMainThreadFactories();
- static void destroyGpuProcess();
std::unique_ptr<base::RunLoop> m_runLoop;
std::unique_ptr<ContentMainDelegateQt> m_mainDelegate;
@@ -121,7 +115,6 @@ private:
static scoped_refptr<QtWebEngineCore::WebEngineContext> m_handle;
static bool m_destroyed;
static bool m_closingDown;
- static QAtomicPointer<gpu::SyncPointManager> s_syncPointManager;
};
} // namespace
diff --git a/src/core/web_engine_context_threads.cpp b/src/core/web_engine_context_threads.cpp
deleted file mode 100644
index f62e2074e..000000000
--- a/src/core/web_engine_context_threads.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-// Copyright (C) 2018 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "web_engine_context.h"
-
-#include "base/bind.h"
-#include "base/task/thread_pool.h"
-#include "base/threading/platform_thread.h"
-#include "base/threading/thread_restrictions.h"
-#include "content/browser/gpu/gpu_main_thread_factory.h"
-#include "content/browser/renderer_host/render_process_host_impl.h"
-#include "content/browser/utility_process_host.h"
-#include "content/child/child_process.h"
-#include "content/gpu/gpu_child_thread.h"
-#include "content/gpu/in_process_gpu_thread.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/renderer/in_process_renderer_thread.h"
-#include "content/utility/in_process_utility_thread.h"
-#include "gpu/ipc/service/gpu_init.h"
-
-#include <memory>
-
-#include <QEventLoop>
-
-namespace QtWebEngineCore {
-
-struct GpuThreadControllerQt : content::GpuThreadController
-{
- GpuThreadControllerQt(const content::InProcessChildThreadParams &params, const gpu::GpuPreferences &gpuPreferences)
- {
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&GpuThreadControllerQt::createGpuProcess, params, gpuPreferences));
- }
- ~GpuThreadControllerQt() override
- {
- content::GetUIThreadTaskRunner({})->PostTask(
- FROM_HERE,
- base::BindOnce(&GpuThreadControllerQt::destroyGpuProcess));
- }
-
- static void createGpuProcess(
- const content::InProcessChildThreadParams &params,
- const gpu::GpuPreferences &gpuPreferences)
- {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (s_gpuProcessDestroyed)
- return;
-
- s_gpuProcess = std::make_unique<content::ChildProcess>(base::ThreadType::kDefault);
- auto gpuInit = std::make_unique<gpu::GpuInit>();
- gpuInit->InitializeInProcess(base::CommandLine::ForCurrentProcess(), gpuPreferences);
- auto childThread = new content::GpuChildThread(params, std::move(gpuInit));
- childThread->Init(base::TimeTicks::Now());
- s_gpuProcess->set_main_thread(childThread);
- }
-
- static void destroyGpuProcess()
- {
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- if (s_gpuProcessDestroyed)
- return;
-
- // viz::GpuServiceImpl::~GpuServiceImpl waits for io task.
- base::ScopedAllowBaseSyncPrimitivesForTesting allow;
- s_gpuProcess.reset();
- s_gpuProcessDestroyed = true;
- }
-
- static std::unique_ptr<content::ChildProcess> s_gpuProcess;
- static bool s_gpuProcessDestroyed;
-};
-
-std::unique_ptr<content::ChildProcess> GpuThreadControllerQt::s_gpuProcess;
-bool GpuThreadControllerQt::s_gpuProcessDestroyed = false;
-
-static std::unique_ptr<content::GpuThreadController> createGpuThreadController(
- const content::InProcessChildThreadParams &params,
- const gpu::GpuPreferences &gpuPreferences)
-{
- return std::make_unique<GpuThreadControllerQt>(params, gpuPreferences);
-}
-
-// static
-void WebEngineContext::destroyGpuProcess()
-{
- GpuThreadControllerQt::destroyGpuProcess();
-}
-
-// static
-void WebEngineContext::registerMainThreadFactories()
-{
- content::UtilityProcessHost::RegisterUtilityMainThreadFactory(content::CreateInProcessUtilityThread);
- content::RenderProcessHostImpl::RegisterRendererMainThreadFactory(content::CreateInProcessRendererThread);
- if (!isGpuServiceOnUIThread())
- content::RegisterGpuMainThreadFactory(content::CreateInProcessGpuThread);
- else
- content::RegisterGpuMainThreadFactory(createGpuThreadController);
-}
-
-} // namespace QtWebEngineCore
diff --git a/src/core/web_engine_error.h b/src/core/web_engine_error.h
index 88766f9c0..b43678ad2 100644
--- a/src/core/web_engine_error.h
+++ b/src/core/web_engine_error.h
@@ -17,7 +17,7 @@
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
-class Q_WEBENGINECORE_PRIVATE_EXPORT WebEngineError
+class Q_WEBENGINECORE_EXPORT WebEngineError
{
public:
diff --git a/src/core/web_engine_library_info.cpp b/src/core/web_engine_library_info.cpp
index 588af5cc6..e71153899 100644
--- a/src/core/web_engine_library_info.cpp
+++ b/src/core/web_engine_library_info.cpp
@@ -57,7 +57,7 @@ static QString getBundlePath(CFBundleRef frameworkBundle)
// The following is a fix for QtWebEngineProcess crashes on OS X 10.7 and before.
// We use it for the other OS X versions as well to make sure it works and because
// the directory structure should be the same.
- if (qApp->applicationName() == QLatin1String(QTWEBENGINEPROCESS_NAME)) {
+ if (qApp->applicationName() == QLatin1String(qWebEngineProcessName())) {
path = QDir::cleanPath(qApp->applicationDirPath() % QLatin1String("/../../../.."));
} else if (frameworkBundle) {
CFURLRef bundleUrl = CFBundleCopyBundleURL(frameworkBundle);
@@ -75,7 +75,7 @@ static QString getResourcesPath(CFBundleRef frameworkBundle)
// The following is a fix for QtWebEngineProcess crashes on OS X 10.7 and before.
// We use it for the other OS X versions as well to make sure it works and because
// the directory structure should be the same.
- if (qApp->applicationName() == QLatin1String(QTWEBENGINEPROCESS_NAME)) {
+ if (qApp->applicationName() == QLatin1String(qWebEngineProcessName())) {
path = getBundlePath(frameworkBundle) % QLatin1String("/Resources");
} else if (frameworkBundle) {
CFURLRef resourcesRelativeUrl = CFBundleCopyResourcesDirectoryURL(frameworkBundle);
@@ -121,9 +121,9 @@ QString subProcessPath()
static QString processPath;
if (processPath.isEmpty()) {
#if defined(Q_OS_WIN)
- const QString processBinary = QLatin1String(QTWEBENGINEPROCESS_NAME) % QLatin1String(".exe");
+ const QString processBinary = QLatin1String(qWebEngineProcessName()) % QLatin1String(".exe");
#else
- const QString processBinary = QLatin1String(QTWEBENGINEPROCESS_NAME);
+ const QString processBinary = QLatin1String(qWebEngineProcessName());
#endif
QStringList candidatePaths;
@@ -133,8 +133,9 @@ QString subProcessPath()
candidatePaths << fromEnv;
} else {
#if defined(Q_OS_DARWIN) && defined(QT_MAC_FRAMEWORK_BUILD)
- candidatePaths << getBundlePath(frameworkBundle())
- % QStringLiteral("/Helpers/" QTWEBENGINEPROCESS_NAME ".app/Contents/MacOS/" QTWEBENGINEPROCESS_NAME);
+ candidatePaths << getBundlePath(frameworkBundle()) % QStringLiteral("/Helpers/")
+ % qWebEngineProcessName() % QStringLiteral(".app/Contents/MacOS/")
+ % qWebEngineProcessName();
#else
candidatePaths << QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath)
% QLatin1Char('/') % processBinary;
@@ -283,6 +284,12 @@ QString dictionariesPath()
break;
}
}
+
+ if (potentialDictionariesPath.isEmpty()) {
+ // return path for error message
+ potentialDictionariesPath = QCoreApplication::applicationDirPath() % QDir::separator()
+ % QLatin1String("qtwebengine_dictionaries");
+ }
}
return potentialDictionariesPath;
@@ -377,6 +384,8 @@ base::FilePath WebEngineLibraryInfo::getPath(int key)
case base::DIR_APP_DICTIONARIES:
return toFilePath(dictionariesPath());
#endif
+ case base::DIR_ASSETS:
+ return toFilePath(resourcesPath());
default:
// Note: the path system expects this function to override the default
// behavior. So no need to log an error if we don't support a given
diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp
index 906f9fb72..e302998f0 100644
--- a/src/core/web_engine_settings.cpp
+++ b/src/core/web_engine_settings.cpp
@@ -9,7 +9,6 @@
#include "base/command_line.h"
#include "chrome/common/chrome_switches.h"
-#include "content/browser/gpu/gpu_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
@@ -57,10 +56,25 @@ static inline bool isTouchEventsAPIEnabled() {
return touchEventsAPIEnabled;
}
+blink::mojom::ImageAnimationPolicy
+toBlinkImageAnimationPolicy(QWebEngineSettings::ImageAnimationPolicy policy)
+{
+ switch (policy) {
+ case QWebEngineSettings::AllowImageAnimation:
+ return blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyAllowed;
+ case QWebEngineSettings::AnimateImageOnce:
+ return blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyAnimateOnce;
+ case QWebEngineSettings::DisallowImageAnimation:
+ return blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyNoAnimation;
+ }
+ return blink::mojom::ImageAnimationPolicy::kImageAnimationPolicyAllowed;
+}
+
WebEngineSettings::WebEngineSettings(WebEngineSettings *_parentSettings)
: m_adapter(nullptr)
, parentSettings(_parentSettings)
, m_unknownUrlSchemePolicy(QWebEngineSettings::InheritedUnknownUrlSchemePolicy)
+ , m_imageAnimationPolicy(QWebEngineSettings::InheritedImageAnimationPolicy)
{
if (parentSettings)
parentSettings->childSettings.insert(this);
@@ -192,6 +206,24 @@ QString WebEngineSettings::defaultTextEncoding() const
void WebEngineSettings::setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy)
{
m_unknownUrlSchemePolicy = policy;
+ scheduleApplyRecursively();
+}
+
+void WebEngineSettings::setImageAnimationPolicy(QWebEngineSettings::ImageAnimationPolicy policy)
+{
+ m_imageAnimationPolicy = policy;
+ scheduleApplyRecursively();
+}
+
+QWebEngineSettings::ImageAnimationPolicy WebEngineSettings::imageAnimationPolicy() const
+{
+ if (m_imageAnimationPolicy != QWebEngineSettings::InheritedImageAnimationPolicy)
+ return m_imageAnimationPolicy;
+
+ if (parentSettings)
+ return parentSettings->imageAnimationPolicy();
+
+ return QWebEngineSettings::AllowImageAnimation;
}
QWebEngineSettings::UnknownUrlSchemePolicy WebEngineSettings::unknownUrlSchemePolicy() const
@@ -262,6 +294,11 @@ void WebEngineSettings::initDefaults()
s_defaultAttributes.insert(QWebEngineSettings::PdfViewerEnabled, false);
#endif
s_defaultAttributes.insert(QWebEngineSettings::NavigateOnDropEnabled, true);
+ bool noReadingFromCanvas =
+ commandLine->HasSwitch(switches::kDisableReadingFromCanvas);
+ s_defaultAttributes.insert(QWebEngineSettings::ReadingFromCanvasEnabled, !noReadingFromCanvas);
+ bool forceDarkMode = commandLine->HasSwitch(switches::kForceDarkMode);
+ s_defaultAttributes.insert(QWebEngineSettings::ForceDarkMode, forceDarkMode);
}
if (s_defaultFontFamilies.isEmpty()) {
@@ -296,6 +333,7 @@ void WebEngineSettings::initDefaults()
m_defaultEncoding = QStringLiteral("ISO-8859-1");
m_unknownUrlSchemePolicy = QWebEngineSettings::InheritedUnknownUrlSchemePolicy;
+ m_imageAnimationPolicy = QWebEngineSettings::InheritedImageAnimationPolicy;
}
void WebEngineSettings::scheduleApply()
@@ -321,6 +359,9 @@ void WebEngineSettings::doApply()
void WebEngineSettings::applySettingsToWebPreferences(blink::web_pref::WebPreferences *prefs)
{
+ // Not supported
+ prefs->picture_in_picture_enabled = false;
+
// Override for now
prefs->touch_event_feature_detection_enabled = isTouchEventsAPIEnabled();
#if !QT_CONFIG(webengine_embedded_build)
@@ -355,6 +396,7 @@ void WebEngineSettings::applySettingsToWebPreferences(blink::web_pref::WebPrefer
prefs->fullscreen_supported = testAttribute(QWebEngineSettings::FullScreenSupportEnabled);
prefs->accelerated_2d_canvas_enabled =
testAttribute(QWebEngineSettings::Accelerated2dCanvasEnabled);
+ prefs->force_dark_mode_enabled = testAttribute(QWebEngineSettings::ForceDarkMode);
prefs->webgl1_enabled = prefs->webgl2_enabled = testAttribute(QWebEngineSettings::WebGLEnabled);
prefs->should_print_backgrounds = testAttribute(QWebEngineSettings::PrintElementBackgrounds);
prefs->allow_running_insecure_content =
@@ -369,7 +411,8 @@ void WebEngineSettings::applySettingsToWebPreferences(blink::web_pref::WebPrefer
}
prefs->dom_paste_enabled = testAttribute(QWebEngineSettings::JavascriptCanPaste);
prefs->dns_prefetching_enabled = testAttribute(QWebEngineSettings::DnsPrefetchEnabled);
- prefs->navigate_on_drag_drop = testAttribute(QWebEngineSettings::NavigateOnDropEnabled);
+ prefs->disable_reading_from_canvas = !testAttribute(QWebEngineSettings::ReadingFromCanvasEnabled);
+ prefs->animation_policy = toBlinkImageAnimationPolicy(imageAnimationPolicy());
// Fonts settings.
prefs->standard_font_family_map[blink::web_pref::kCommonScript] =
@@ -441,6 +484,11 @@ bool WebEngineSettings::applySettingsToRendererPreferences(blink::RendererPrefer
}
}
#endif
+ bool canNavigateOnDrop = testAttribute(QWebEngineSettings::NavigateOnDropEnabled);
+ if (canNavigateOnDrop != prefs->can_accept_load_drops) {
+ prefs->can_accept_load_drops = canNavigateOnDrop;
+ changed = true;
+ }
return changed;
}
diff --git a/src/core/web_engine_settings.h b/src/core/web_engine_settings.h
index 51f511155..2bfc5949d 100644
--- a/src/core/web_engine_settings.h
+++ b/src/core/web_engine_settings.h
@@ -67,6 +67,9 @@ public:
void setUnknownUrlSchemePolicy(QWebEngineSettings::UnknownUrlSchemePolicy policy);
QWebEngineSettings::UnknownUrlSchemePolicy unknownUrlSchemePolicy() const;
+ void setImageAnimationPolicy(QWebEngineSettings::ImageAnimationPolicy policy);
+ QWebEngineSettings::ImageAnimationPolicy imageAnimationPolicy() const;
+
void scheduleApply();
void scheduleApplyRecursively();
@@ -95,6 +98,7 @@ private:
static QHash<QWebEngineSettings::FontFamily, QString> s_defaultFontFamilies;
static QHash<QWebEngineSettings::FontSize, int> s_defaultFontSizes;
QWebEngineSettings::UnknownUrlSchemePolicy m_unknownUrlSchemePolicy;
+ QWebEngineSettings::ImageAnimationPolicy m_imageAnimationPolicy;
friend class WebContentsAdapter;
};
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index 508a4b557..617eea2d0 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -35,6 +35,7 @@
#include "ui/events/keycodes/dom/keycode_converter.h"
#include "ui/events/keycodes/keyboard_code_conversion.h"
+#include "native_web_keyboard_event_qt.h"
#include "render_widget_host_view_qt_delegate.h"
#include <QtGui/private/qtgui-config_p.h>
@@ -558,6 +559,8 @@ static int windowsKeyCodeForQtKey(int qtKey, bool isKeypad)
case Qt::Key_QuoteDbl:
return VK_OEM_7; // case '\'': case '"': return 0xDE;
// VK_OEM_8 (DF) Used for miscellaneous characters; it can vary by keyboard.
+ case Qt::Key_AltGr:
+ return 0xE1; // (E1) VK_OEM_AX = ui::VKEY_ALTGR see ui/events/keycodes/keyboard_codes_win.h
// VK_OEM_102 (E2) Windows 2000/XP: Either the angle bracket key or the backslash key on the RT 102-key keyboard
case Qt::Key_AudioRewind:
@@ -1442,6 +1445,7 @@ WebMouseEvent WebEventFactory::toWebMouseEvent(QHoverEvent *ev)
webKitEvent.SetType(webEventTypeForEvent(ev));
webKitEvent.SetPositionInWidget(ev->position().x(), ev->position().y());
+ webKitEvent.SetPositionInScreen(ev->globalPosition().x(), ev->globalPosition().y());
webKitEvent.movement_x = ev->position().x() - ev->oldPos().x();
webKitEvent.movement_y = ev->position().y() - ev->oldPos().y();
webKitEvent.is_raw_movement_event = true;
@@ -1541,8 +1545,9 @@ static QPoint getWheelEventDelta(const blink::WebGestureEvent &webEvent)
{
static const float cDefaultQtScrollStep = 20.f;
static const int wheelScrollLines = QGuiApplication::styleHints()->wheelScrollLines();
- return QPoint(webEvent.data.scroll_update.delta_x * QWheelEvent::DefaultDeltasPerStep / (wheelScrollLines * cDefaultQtScrollStep),
- webEvent.data.scroll_update.delta_y * QWheelEvent::DefaultDeltasPerStep / (wheelScrollLines * cDefaultQtScrollStep));
+ static const float deltasPerStep = static_cast<float>(QWheelEvent::DefaultDeltasPerStep);
+ return QPoint(webEvent.data.scroll_update.delta_x * deltasPerStep / (wheelScrollLines * cDefaultQtScrollStep),
+ webEvent.data.scroll_update.delta_y * deltasPerStep / (wheelScrollLines * cDefaultQtScrollStep));
}
blink::WebMouseWheelEvent::Phase toBlinkPhase(QWheelEvent *ev)
@@ -1562,6 +1567,22 @@ blink::WebMouseWheelEvent::Phase toBlinkPhase(QWheelEvent *ev)
return blink::WebMouseWheelEvent::kPhaseNone;
}
+blink::WebMouseWheelEvent::Phase getMomentumPhase(QWheelEvent *ev)
+{
+ switch (ev->phase()) {
+ case Qt::ScrollMomentum:
+ return blink::WebMouseWheelEvent::kPhaseBegan;
+ case Qt::ScrollEnd:
+ return blink::WebMouseWheelEvent::kPhaseEnded;
+ case Qt::NoScrollPhase:
+ case Qt::ScrollBegin:
+ case Qt::ScrollUpdate:
+ return blink::WebMouseWheelEvent::kPhaseNone;
+ }
+ Q_UNREACHABLE();
+ return blink::WebMouseWheelEvent::kPhaseNone;
+}
+
blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev)
{
WebMouseWheelEvent webEvent;
@@ -1573,11 +1594,12 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev)
webEvent.SetPositionInScreen(static_cast<float>(ev->globalPosition().x()),
static_cast<float>(ev->globalPosition().y()));
- webEvent.wheel_ticks_x = static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep;
- webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep;
+ webEvent.wheel_ticks_x = ev->angleDelta().x() / static_cast<float>(QWheelEvent::DefaultDeltasPerStep);
+ webEvent.wheel_ticks_y = ev->angleDelta().y() / static_cast<float>(QWheelEvent::DefaultDeltasPerStep);
webEvent.phase = toBlinkPhase(ev);
#if defined(Q_OS_DARWIN)
// PrecisePixel is a macOS term meaning it is a system scroll gesture, see qnsview_mouse.mm
+ webEvent.momentum_phase = getMomentumPhase(ev);
if (ev->source() == Qt::MouseEventSynthesizedBySystem)
webEvent.delta_units = ui::ScrollGranularity::kScrollByPrecisePixel;
#endif
@@ -1596,6 +1618,9 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent,
if (toBlinkPhase(ev) != webEvent.phase)
return false;
#if defined(Q_OS_DARWIN)
+ if (getMomentumPhase(ev) != webEvent.momentum_phase)
+ return false;
+
if ((webEvent.delta_units == ui::ScrollGranularity::kScrollByPrecisePixel)
!= (ev->source() == Qt::MouseEventSynthesizedBySystem))
return false;
@@ -1607,8 +1632,8 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent,
webEvent.SetPositionInScreen(static_cast<float>(ev->globalPosition().x()),
static_cast<float>(ev->globalPosition().y()));
- webEvent.wheel_ticks_x += static_cast<float>(ev->angleDelta().x()) / QWheelEvent::DefaultDeltasPerStep;
- webEvent.wheel_ticks_y += static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep;
+ webEvent.wheel_ticks_x = ev->angleDelta().x() / static_cast<float>(QWheelEvent::DefaultDeltasPerStep);
+ webEvent.wheel_ticks_y = ev->angleDelta().y() / static_cast<float>(QWheelEvent::DefaultDeltasPerStep);
setBlinkWheelEventDelta(webEvent);
return true;
@@ -1636,13 +1661,17 @@ void WebEventFactory::sendUnhandledWheelEvent(const blink::WebGestureEvent &even
content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *ev)
{
- content::NativeWebKeyboardEvent webKitEvent(reinterpret_cast<gfx::NativeEvent>(ev));
+ content::NativeWebKeyboardEvent webKitEvent(ToNativeEvent(ev));
webKitEvent.SetTimeStamp(base::TimeTicks::Now());
- webKitEvent.SetModifiers(modifiersForEvent(ev));
+ bool isBackTabWithoutModifier =
+ ev->key() == Qt::Key_Backtab && ev->modifiers() == Qt::NoModifier;
+ webKitEvent.SetModifiers(isBackTabWithoutModifier ? WebInputEvent::kShiftKey
+ : modifiersForEvent(ev));
webKitEvent.SetType(webEventTypeForEvent(ev));
int qtKey = qtKeyForKeyEvent(ev);
- Qt::KeyboardModifiers qtModifiers = qtModifiersForEvent(ev);
+ Qt::KeyboardModifiers qtModifiers =
+ isBackTabWithoutModifier ? Qt::ShiftModifier : qtModifiersForEvent(ev);
QString qtText = qtTextForKeyEvent(ev, qtKey, qtModifiers);
webKitEvent.native_key_code = nativeKeyCodeForKeyEvent(ev);
@@ -1677,10 +1706,12 @@ content::NativeWebKeyboardEvent WebEventFactory::toWebKeyboardEvent(QKeyEvent *e
ui::DomCodeToUsLayoutKeyboardCode(static_cast<ui::DomCode>(webKitEvent.dom_code));
const ushort* text = qtText.utf16();
- size_t textSize = std::min(sizeof(webKitEvent.text), size_t(qtText.length() * 2));
- memcpy(&webKitEvent.text, text, textSize);
- memcpy(&webKitEvent.unmodified_text, text, textSize);
-
+ size_t size = std::char_traits<char16_t>::length((char16_t *)text);
+ if (size <= blink::WebKeyboardEvent::kTextLengthCap - 1) { // should be null terminated
+ size_t textSize = std::min(sizeof(webKitEvent.text), size * sizeof(char16_t));
+ memcpy(&webKitEvent.text, text, textSize);
+ memcpy(&webKitEvent.unmodified_text, text, textSize);
+ }
if (webKitEvent.windows_key_code == VK_RETURN) {
// This is the same behavior as GTK:
// We need to treat the enter key as a key press of character \r. This
diff --git a/src/core/web_event_factory.h b/src/core/web_event_factory.h
index dfd50369e..53ebfb509 100644
--- a/src/core/web_event_factory.h
+++ b/src/core/web_event_factory.h
@@ -6,7 +6,7 @@
#include "QtGui/qtguiglobal.h"
-#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/common/input/native_web_keyboard_event.h"
#if QT_CONFIG(gestures)
#include "third_party/blink/public/common/input/web_gesture_event.h"
#endif
diff --git a/src/gn/CMakeLists.txt b/src/gn/CMakeLists.txt
index 3897e123d..0fe3e4e05 100644
--- a/src/gn/CMakeLists.txt
+++ b/src/gn/CMakeLists.txt
@@ -11,7 +11,12 @@ project(Gn
)
if(NOT DEFINED WEBENGINE_ROOT_SOURCE_DIR)
- get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." REALPATH)
+ set(path_mode REALPATH)
+ if(APPLE AND QT_ALLOW_SYMLINK_IN_PATHS)
+ set(path_mode ABSOLUTE)
+ endif()
+
+ get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ${path_mode})
endif()
include(${WEBENGINE_ROOT_SOURCE_DIR}/.cmake.conf)
@@ -26,7 +31,7 @@ find_package(Ninja 1.7.2 REQUIRED)
if(WIN32)
set(GN_EXECUTABLE gn.exe)
- if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+ if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT MINGW)
# Use lld-link instead of clang-cl.
set(GN_LINKER ${CMAKE_LINKER})
endif()
@@ -35,6 +40,21 @@ else()
endif()
file(MAKE_DIRECTORY ${GN_BINARY_DIR})
+
+if((UNIX AND NOT APPLE) AND
+ (CMAKE_CXX_COMPILER_ID STREQUAL GNU OR
+ CMAKE_CXX_COMPILER_ID STREQUAL Clang))
+ set(platform linux)
+elseif(MSVC)
+ set(platform msvc)
+elseif(MINGW)
+ set(platform mingw)
+elseif(APPLE AND CMAKE_CXX_COMPILER_ID STREQUAL AppleClang)
+ set(platform darwin)
+else()
+ message(FATAL_ERROR "Unsupported gn platform !")
+endif()
+
add_custom_command(
OUTPUT ${GN_EXECUTABLE}
WORKING_DIRECTORY ${GN_BINARY_DIR}
@@ -44,6 +64,7 @@ add_custom_command(
--cc ${CMAKE_C_COMPILER}
--cxx ${CMAKE_CXX_COMPILER}
--ld ${GN_LINKER}
+ --platform ${platform}
--ar ${CMAKE_AR}
--qt-version "${QT_REPO_MODULE_VERSION}.qtwebengine.qt.io"
$<$<PLATFORM_ID:Darwin>:--isysroot>
diff --git a/src/host/BUILD.toolchain.gn.in b/src/host/BUILD.toolchain.gn.in
index df62aa88e..1beb9ee6d 100644
--- a/src/host/BUILD.toolchain.gn.in
+++ b/src/host/BUILD.toolchain.gn.in
@@ -12,6 +12,7 @@ gcc_toolchain("@GN_TOOLCHAIN@") {
current_cpu = "@GN_CPU@"
v8_current_cpu = "@GN_V8_CPU@"
is_clang = @GN_IS_CLANG@
+ is_mingw = @GN_IS_MINGW@
use_gold = false
}
}
diff --git a/src/host/CMakeLists.txt b/src/host/CMakeLists.txt
index 2b92ebe85..d40275217 100644
--- a/src/host/CMakeLists.txt
+++ b/src/host/CMakeLists.txt
@@ -19,15 +19,18 @@ project(QtWebEngineConfigure
VERSION "${QT_REPO_MODULE_VERSION}"
LANGUAGES CXX C)
-find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS BuildInternals Core)
+find_package(Qt6 6.5 CONFIG REQUIRED COMPONENTS BuildInternals Core)
+qt_internal_project_setup()
+get_gn_arch(target_arch ${GN_TARGET_CPU})
+get_gn_arch(host_arch ${TEST_architecture_arch})
+get_v8_arch(v8_arch ${target_arch} ${host_arch})
set(buildDir ${CMAKE_CURRENT_BINARY_DIR})
-configure_gn_toolchain(host ${TEST_architecture_arch} ${TEST_architecture_arch}
+configure_gn_toolchain(host ${host_arch} ${host_arch}
${WEBENGINE_ROOT_SOURCE_DIR}/src/host/BUILD.toolchain.gn.in
${buildDir}/host_toolchain
)
-get_v8_arch(GN_V8_HOST_CPU ${GN_TARGET_CPU} ${TEST_architecture_arch})
-configure_gn_toolchain(v8 ${GN_V8_HOST_CPU} ${GN_TARGET_CPU}
+configure_gn_toolchain(v8 ${v8_arch} ${target_arch}
${WEBENGINE_ROOT_SOURCE_DIR}/src/host/BUILD.toolchain.gn.in
${buildDir}/v8_toolchain)
@@ -48,3 +51,18 @@ if(QT_FEATURE_qtpdf_build)
)
endif()
+# TODO: this could be run as part of main configure with execute_process
+# Skip for qtpdf(android)
+
+if(CMAKE_CXX_COMPILER_ID STREQUAL GNU AND TEST_architecture_arch STREQUAL "x86_64"
+ AND GN_TARGET_CPU STREQUAL "arm" AND NOT MINGW AND NOT ANDROID)
+ try_compile(
+ has32HostCompiler
+ "${CMAKE_CURRENT_BINARY_DIR}/config.tests/hostcompiler"
+ "${CMAKE_CURRENT_SOURCE_DIR}/config.tests/hostcompiler"
+ hostcompiler
+ )
+ if(NOT has32HostCompiler)
+ MESSAGE(FATAL_ERROR "Compiler does not support 32bit compilation")
+ endif()
+endif()
diff --git a/src/host/config.tests/hostcompiler/CMakeLists.txt b/src/host/config.tests/hostcompiler/CMakeLists.txt
new file mode 100644
index 000000000..f36886d0a
--- /dev/null
+++ b/src/host/config.tests/hostcompiler/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+cmake_minimum_required(VERSION 3.16)
+project(arch LANGUAGES CXX)
+
+add_executable(host_compiler_test)
+set_property(TARGET host_compiler_test PROPERTY MACOSX_BUNDLE FALSE)
+target_sources(host_compiler_test PRIVATE main.cpp)
+target_compile_options(host_compiler_test PRIVATE -m32)
+target_link_options(host_compiler_test PRIVATE -m32)
diff --git a/src/host/config.tests/hostcompiler/main.cpp b/src/host/config.tests/hostcompiler/main.cpp
new file mode 100644
index 000000000..9cd16a2e3
--- /dev/null
+++ b/src/host/config.tests/hostcompiler/main.cpp
@@ -0,0 +1,9 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: BSD-3-Clause
+
+#include <stdio.h>
+int main()
+{
+ printf("This works\n");
+ return 0;
+}
diff --git a/src/pdf/CMakeLists.txt b/src/pdf/CMakeLists.txt
index de0d42a94..4a54b816e 100644
--- a/src/pdf/CMakeLists.txt
+++ b/src/pdf/CMakeLists.txt
@@ -3,7 +3,7 @@
cmake_minimum_required(VERSION 3.19)
find_package(Ninja 1.7.2 REQUIRED)
-find_package(Nodejs 12 REQUIRED)
+find_package(Nodejs 14.19 REQUIRED)
find_package(PkgConfig)
if(PkgConfig_FOUND)
create_pkg_config_host_wrapper(${CMAKE_CURRENT_BINARY_DIR})
@@ -22,7 +22,7 @@ qt_internal_add_module(Pdf
qpdfdocumentrenderoptions.h
qpdffile.cpp qpdffile_p.h
qpdflink.cpp qpdflink.h qpdflink_p.h
- qpdflinkmodel.cpp qpdflinkmodel_p.h qpdflinkmodel_p_p.h
+ qpdflinkmodel.cpp qpdflinkmodel.h qpdflinkmodel_p.h
qpdfpagenavigator.cpp qpdfpagenavigator.h
qpdfpagerenderer.cpp qpdfpagerenderer.h
qpdfsearchmodel.cpp qpdfsearchmodel.h qpdfsearchmodel_p.h
@@ -32,17 +32,21 @@ qt_internal_add_module(Pdf
../3rdparty/chromium
DEFINES
QT_BUILD_PDF_LIB
- NOMINMAX
LIBRARIES
Qt::CorePrivate
Qt::Network
PUBLIC_LIBRARIES
Qt::Core
Qt::Gui
+ GENERATE_CPP_EXPORTS
)
add_subdirectory(plugins/imageformats/pdf)
+get_install_config(config)
+get_architectures(archs)
+list(GET archs 0 arch)
+
##
# PDF DOCS
##
@@ -51,12 +55,22 @@ qt_internal_add_docs(Pdf
doc/qtpdf.qdocconf
)
+add_code_attributions_target(
+ TARGET generate_pdf_attributions
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/pdf_attributions.qdoc
+ GN_TARGET :QtPdf
+ FILE_TEMPLATE doc/about_credits.tmpl
+ ENTRY_TEMPLATE doc/about_credits_entry.tmpl
+ BUILDDIR ${buildDir}/${config}/${arch}
+)
+add_dependencies(generate_pdf_attributions run_pdf_GnDone)
+add_dependencies(prepare_docs_Pdf generate_pdf_attributions)
##
# TOOLCHAIN SETUP
##
-if(LINUX)
+if(LINUX OR MINGW OR ANDROID)
setup_toolchains()
endif()
@@ -106,34 +120,50 @@ foreach(arch ${archs})
qt_libjpeg_config="${buildDir}/${config}/${arch}:qt_libjpeg_config"
qt_harfbuzz_config="${buildDir}/${config}/${arch}:qt_harfbuzz_config"
qt_freetype_config="${buildDir}/${config}/${arch}:qt_freetype_config"
+ enable_swiftshader=false
+ enable_swiftshader_vulkan=false
+ angle_enable_swiftshader=false
+ dawn_use_swiftshader=false
+ use_dawn=false
+ build_dawn_tests=false
enable_ipc_fuzzer=false
enable_remoting=false
enable_resource_allowlist_generation=false
+ enable_vr=false
enable_web_speech=false
chrome_pgo_phase=0
strip_absolute_paths_from_debug_symbols=false
+ use_perfetto_client_library=false
+ v8_enable_webassembly=false
)
- if(LINUX)
+ if(LINUX OR ANDROID)
list(APPEND gnArgArg
is_cfi=false
ozone_auto_platforms=false
- use_gnome_keyring=false)
+ enable_arcore=false
+ use_ml_inliner=false
+ )
extend_gn_list(gnArgArg
ARGS use_system_icu
CONDITION QT_FEATURE_webengine_system_icu
)
+ extend_gn_list(gnArgArg
+ ARGS use_system_libopenjpeg2
+ CONDITION QT_FEATURE_webengine_system_libopenjpeg2
+ )
endif()
if(MACOS)
list(APPEND gnArgArg angle_enable_vulkan=false)
endif()
if(IOS)
+ list(APPEND gnArgArg enable_base_tracing=false)
extend_gn_list(gnArgArg
ARGS enable_ios_bitcode
CONDITION QT_FEATURE_pdf_bitcode
)
endif()
- if(WIN32)
+ if(WIN32 OR ANDROID)
list(APPEND gnArgArg
ninja_use_custom_environment_files=false
safe_browsing_mode=0
@@ -169,10 +199,22 @@ foreach(arch ${archs})
CONDITION QT_FEATURE_pdf_xfa_tiff
)
extend_gn_list(gnArgArg
+ ARGS pdfium_use_system_zlib use_system_zlib
+ CONDITION QT_FEATURE_webengine_system_zlib
+ )
+ extend_gn_list(gnArgArg
+ ARGS pdfium_use_system_libpng use_system_libpng
+ CONDITION QT_FEATURE_webengine_system_libpng
+ )
+ extend_gn_list(gnArgArg
ARGS pdfium_use_qt_libpng
CONDITION QT_FEATURE_webengine_qt_libpng
)
extend_gn_list(gnArgArg
+ ARGS pdfium_use_system_libtiff
+ CONDITION QT_FEATURE_webengine_system_libtiff
+ )
+ extend_gn_list(gnArgArg
ARGS use_qt_libjpeg
CONDITION QT_FEATURE_webengine_qt_libjpeg
)
@@ -189,7 +231,7 @@ foreach(arch ${archs})
CMAKE_TARGET Pdf
NINJA_TARGETS QtPdf
GN_TARGET ${buildGn}
- GN_ARGS "${gnArgArg}"
+ GN_ARGS ${gnArgArg}
BUILDDIR ${buildDir}/${config}/${arch}
MODULE pdf
)
@@ -206,6 +248,13 @@ endforeach()
get_architectures(archs)
list(GET archs 0 arch)
target_include_directories(Pdf PRIVATE ${buildDir}/$<CONFIG>/${arch}/gen)
-add_gn_build_aritfacts_to_target(Pdf QtPdf pdf ${buildDir} TRUE)
+add_gn_build_artifacts_to_target(
+ CMAKE_TARGET Pdf
+ NINJA_TARGET QtPdf
+ MODULE pdf
+ BUILDDIR ${buildDir}
+ COMPLETE_STATIC TRUE
+ NINJA_STAMP QtPdf.stamp
+)
add_dependencies(Pdf run_pdf_NinjaDone)
diff --git a/src/pdf/configure/BUILD.root.gn.in b/src/pdf/configure/BUILD.root.gn.in
index da41d80cc..e9f54ed6d 100644
--- a/src/pdf/configure/BUILD.root.gn.in
+++ b/src/pdf/configure/BUILD.root.gn.in
@@ -39,30 +39,35 @@ config("QtPdf_config") {
]
}
-config("cpp17_config") {
- # static initialized constexpr expressions must be compiled always as c++14 or always as c++17
- # and our qtwebengine core sources use them as c++17
+config("cpp20_config") {
+ # Chromium headers now use concepts and requires c++20
if (is_win) {
- cflags_cc = [ "/std:c++17" ]
+ cflags_cc = [ "/std:c++20" ]
} else {
- cflags_cc = [ "-std=c++17" ]
+ cflags_cc = [ "-std=c++20" ]
}
}
static_library("QtPdf") {
complete_static_lib = true
- rsp_types = [ "objects", "archives", "libs" ]
+ rsp_types = [ "objects", "archives", "libs", "ldir" ]
configs += [
- ":cpp17_config",
+ ":cpp20_config",
":QtPdf_config"
]
deps = [
"//third_party/pdfium"
]
- if (is_win) {
+ if (is_msvc) {
libs = [
"dloadhelper.lib",
"winmm.lib",
+ "usp10.lib",
+ ]
+ }
+ if (is_mingw) {
+ libs = [
+ "winmm",
]
}
}
diff --git a/src/pdf/doc/about_credits.tmpl b/src/pdf/doc/about_credits.tmpl
new file mode 100644
index 000000000..57fae9e78
--- /dev/null
+++ b/src/pdf/doc/about_credits.tmpl
@@ -0,0 +1 @@
+{{entries}}
diff --git a/src/pdf/doc/about_credits_entry.tmpl b/src/pdf/doc/about_credits_entry.tmpl
new file mode 100644
index 000000000..294198709
--- /dev/null
+++ b/src/pdf/doc/about_credits_entry.tmpl
@@ -0,0 +1,13 @@
+/*!
+\page qtpdf-3rdparty-{{name-sanitized}}.html
+\attribution
+\ingroup qtpdf-licensing
+\brief {{license-type}}
+\title {{name}}
+
+\l{{{url}}}{Project Homepage}
+
+\badcode
+{{license}}
+\endcode
+*/
diff --git a/src/pdf/doc/images/pdfviewer.png b/src/pdf/doc/images/pdfviewer.png
new file mode 100644
index 000000000..ac8a31ac0
--- /dev/null
+++ b/src/pdf/doc/images/pdfviewer.png
Binary files differ
diff --git a/src/pdf/doc/images/singlepageviewer.webp b/src/pdf/doc/images/singlepageviewer.webp
new file mode 100644
index 000000000..e429cb818
--- /dev/null
+++ b/src/pdf/doc/images/singlepageviewer.webp
Binary files differ
diff --git a/src/pdf/doc/qtpdf.qdocconf b/src/pdf/doc/qtpdf.qdocconf
index d55f88a41..d0340fe83 100644
--- a/src/pdf/doc/qtpdf.qdocconf
+++ b/src/pdf/doc/qtpdf.qdocconf
@@ -63,5 +63,5 @@ navigation.landingpage = "Qt PDF"
navigation.cppclassespage = "Qt PDF C++ Classes"
navigation.qmltypespage = "Qt Quick PDF QML Types"
-# Fail the documentation build if there are more warnings than the limit
+# Enforce zero documentation warnings
warninglimit = 0
diff --git a/src/pdf/doc/src/qtpdf-examples.qdoc b/src/pdf/doc/src/qtpdf-examples.qdoc
index 0ebad3c82..02dc23dc2 100644
--- a/src/pdf/doc/src/qtpdf-examples.qdoc
+++ b/src/pdf/doc/src/qtpdf-examples.qdoc
@@ -3,7 +3,6 @@
/*!
\group qtpdf-examples
- \ingroup all-examples
\title Qt PDF Examples
\brief Using the classes and types in the Qt PDF module.
diff --git a/src/pdf/doc/src/qtpdf-index.qdoc b/src/pdf/doc/src/qtpdf-index.qdoc
index 07c151f47..b72619fbf 100644
--- a/src/pdf/doc/src/qtpdf-index.qdoc
+++ b/src/pdf/doc/src/qtpdf-index.qdoc
@@ -17,7 +17,7 @@
and holds the search results. The QPdfBookmarkModel class holds the
table of contents, if present. The QPdfLinkModel holds information
about hyperlinks on a page. The \l QPdfView widget is a complete
- PDF viewer, and the \l {PDF Viewer Example} shows how to use it.
+ PDF viewer, and the \l {PDF Viewer Widget Example} shows how to use it.
For Qt Quick applications, three kinds of full-featured viewer
components are provided. \l PdfMultiPageView should be your
@@ -64,4 +64,17 @@
\li \l{Qt PDF C++ Classes}
\li \l{Qt Quick PDF QML Types}
\endlist
+
+ \section1 Articles and Guides
+ \list
+ \li {Qt PDF Platform Notes} {Platform Notes}
+ \endlist
+
+ \section1 Licenses and Attributions
+
+ Qt PDF is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under the
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt PDF Licensing} for further details about this module.
*/
diff --git a/src/pdf/doc/src/qtpdf-licensing.qdoc b/src/pdf/doc/src/qtpdf-licensing.qdoc
new file mode 100644
index 000000000..190ee8331
--- /dev/null
+++ b/src/pdf/doc/src/qtpdf-licensing.qdoc
@@ -0,0 +1,18 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \group qtpdf-licensing
+ \title Qt PDF Licensing
+
+ Qt PDF is available under commercial licenses from \l{The Qt Company}.
+ In addition, it is available under the
+ \l{GNU Lesser General Public License, version 3}, or
+ the \l{GNU General Public License, version 2}.
+ See \l{Qt Licensing} for further details.
+
+ The module includes a snapshot of PDFium. As such, users need to respect
+ the licenses of PDFium and third-party code included in it.
+
+ Third party licenses included in the sources are:
+*/
diff --git a/src/pdf/doc/src/qtpdf-platformnotes.qdoc b/src/pdf/doc/src/qtpdf-platformnotes.qdoc
new file mode 100644
index 000000000..f50be120d
--- /dev/null
+++ b/src/pdf/doc/src/qtpdf-platformnotes.qdoc
@@ -0,0 +1,11 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+
+/*!
+ \page qtpdf-platformnotes.html
+ \title Qt PDF Platform Notes
+
+ Building Qt PDF for Android is currently
+ \l{https://bugreports.qt.io/browse/QTBUG-83459} {not supported} on Windows host platforms.
+*/
+
diff --git a/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp b/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp
index 195759028..bb3e7c929 100644
--- a/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp
+++ b/src/pdf/plugins/imageformats/pdf/qpdfiohandler.cpp
@@ -62,7 +62,7 @@ int QPdfIOHandler::imageCount() const
bool QPdfIOHandler::read(QImage *image)
{
if (load(device())) {
- if (m_page >= m_doc->pageCount())
+ if (m_doc.isNull() || m_page >= m_doc->pageCount())
return false;
if (m_page < 0)
m_page = 0;
@@ -110,9 +110,11 @@ bool QPdfIOHandler::read(QImage *image)
options.setScaledSize(pageSize);
image->fill(m_backColor.rgba());
QPainter p(image);
- QImage pageImage = m_doc->render(m_page, finalSize, options);
- p.drawImage(0, 0, pageImage);
- p.end();
+ if (!m_doc.isNull()) {
+ QImage pageImage = m_doc->render(m_page, finalSize, options);
+ p.drawImage(0, 0, pageImage);
+ p.end();
+ }
}
return true;
}
diff --git a/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h b/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h
index 5918c0328..c4d8e0f9a 100644
--- a/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h
+++ b/src/pdf/plugins/imageformats/pdf/qpdfiohandler_p.h
@@ -41,7 +41,7 @@ private:
bool load(QIODevice *device);
private:
- QPdfDocument *m_doc = nullptr;
+ QPointer<QPdfDocument> m_doc;
int m_page = -1;
QRect m_clipRect;
diff --git a/src/pdf/qpdfbookmarkmodel.cpp b/src/pdf/qpdfbookmarkmodel.cpp
index c9035f21a..93dbf5d1f 100644
--- a/src/pdf/qpdfbookmarkmodel.cpp
+++ b/src/pdf/qpdfbookmarkmodel.cpp
@@ -176,17 +176,7 @@ struct QPdfBookmarkModelPrivate
const FPDF_DEST dest = FPDFBookmark_GetDest(document, bookmark);
const int pageNumber = FPDFDest_GetDestPageIndex(document, dest);
- double pageHeight = 11.69 * 72; // A4 height
- {
- // get actual page height
- const QPdfMutexLocker lock;
- FPDF_PAGE pdfPage = FPDF_LoadPage(document, pageNumber);
- if (pdfPage)
- pageHeight = FPDF_GetPageHeight(pdfPage);
- else
- qCWarning(qLcBM) << "failed to load page" << pageNumber;
- }
-
+ const qreal pageHeight = m_document->pagePointSize(pageNumber).height();
FPDF_BOOL hasX, hasY, hasZoom;
FS_FLOAT x, y, zoom;
bool ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom);
@@ -270,6 +260,10 @@ QPdfDocument* QPdfBookmarkModel::document() const
return d->m_document;
}
+/*!
+ \property QPdfBookmarkModel::document
+ \brief the PDF document in which bookmarks are to be found.
+*/
void QPdfBookmarkModel::setDocument(QPdfDocument *document)
{
if (d->m_document == document)
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp
index a3e412c5c..17fdb29b9 100644
--- a/src/pdf/qpdfdocument.cpp
+++ b/src/pdf/qpdfdocument.cpp
@@ -15,6 +15,7 @@
#include <QLoggingCategory>
#include <QMetaEnum>
#include <QMutex>
+#include <QPixmap>
#include <QVector2D>
#include <QtCore/private/qtools_p.h>
@@ -56,6 +57,7 @@ public:
{
if (!index.isValid())
return QVariant();
+
switch (QPdfDocument::PageModelRole(role)) {
case QPdfDocument::PageModelRole::Label:
return document()->pageLabel(index.row());
@@ -64,6 +66,14 @@ public:
case QPdfDocument::PageModelRole::NRoles:
break;
}
+
+ switch (role) {
+ case Qt::DecorationRole:
+ return pageThumbnail(index.row());
+ case Qt::DisplayRole:
+ return document()->pageLabel(index.row());
+ }
+
return QVariant();
}
@@ -73,8 +83,24 @@ public:
private:
QPdfDocument *document() const { return static_cast<QPdfDocument *>(parent()); }
+ QPixmap pageThumbnail(int page) const
+ {
+ auto it = m_thumbnails.constFind(page);
+ if (it == m_thumbnails.constEnd()) {
+ auto doc = document();
+ auto size = doc->pagePointSize(page);
+ size.scale(128, 128, Qt::KeepAspectRatio);
+ // TODO use QPdfPageRenderer for threading?
+ auto image = document()->render(page, size.toSize());
+ QPixmap ret = QPixmap::fromImage(image);
+ m_thumbnails.insert(page, ret);
+ return ret;
+ }
+ return it.value();
+ }
QHash<int, QByteArray> m_roleNames;
+ mutable QHash<int, QPixmap> m_thumbnails;
};
QPdfDocumentPrivate::QPdfDocumentPrivate()
@@ -420,7 +446,7 @@ void QPdfDocumentPrivate::fpdf_AddSegment(_FX_DOWNLOADHINTS *pThis, size_t offse
Q_UNUSED(size);
}
-QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count)
+QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const
{
QList<ushort> buf(count + 1);
// TODO is that enough space in case one unicode character is more than one in utf-16?
@@ -429,23 +455,73 @@ QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int
return QString::fromUtf16(reinterpret_cast<const char16_t *>(buf.constData()), len - 1);
}
-QPointF QPdfDocumentPrivate::getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex)
+QPointF QPdfDocumentPrivate::getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const
{
double x, y;
- int count = FPDFText_CountChars(textPage);
- bool ok = FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y);
- if (!ok)
- return QPointF();
- return QPointF(x, pageHeight - y);
+ const int count = FPDFText_CountChars(textPage);
+ if (FPDFText_GetCharOrigin(textPage, qMin(count - 1, charIndex), &x, &y))
+ return mapPageToView(pdfPage, x, y);
+ return {};
}
-QRectF QPdfDocumentPrivate::getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex)
+QRectF QPdfDocumentPrivate::getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const
{
double l, t, r, b;
- bool ok = FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t);
- if (!ok)
- return QRectF();
- return QRectF(l, pageHeight - t, r - l, t - b);
+ if (FPDFText_GetCharBox(textPage, charIndex, &l, &r, &b, &t))
+ return mapPageToView(pdfPage, l, t, r, b);
+ return {};
+}
+
+/*! \internal
+ Convert the point \a x , \a y to the usual 1x (pixels = points)
+ 4th-quadrant "view" coordinate system relative to the top-left corner of
+ the rendered page. Some PDF files have internal transforms that make this
+ coordinate system different from "page coordinates", so we cannot just
+ subtract from page height to invert the y coordinates, in general.
+ */
+QPointF QPdfDocumentPrivate::mapPageToView(FPDF_PAGE pdfPage, double x, double y) const
+{
+ const auto pageHeight = FPDF_GetPageHeight(pdfPage);
+ const auto pageWidth = FPDF_GetPageWidth(pdfPage);
+ int rx, ry;
+ if (FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, x, y, &rx, &ry))
+ return QPointF(rx, ry);
+ return {};
+}
+
+/*! \internal
+ Convert the bounding box defined by \a left \a top \a right and \a bottom
+ to the usual 1x (pixels = points) 4th-quadrant "view" coordinate system
+ that we use for rendering things on top of the page image.
+ Some PDF files have internal transforms that make this coordinate
+ system different from "page coordinates", so we cannot just
+ subtract from page height to invert the y coordinates, in general.
+ */
+QRectF QPdfDocumentPrivate::mapPageToView(FPDF_PAGE pdfPage, double left, double top, double right, double bottom) const
+{
+ const auto pageHeight = FPDF_GetPageHeight(pdfPage);
+ const auto pageWidth = FPDF_GetPageWidth(pdfPage);
+ int xfmLeft, xfmTop, xfmRight, xfmBottom;
+ if ( FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, left, top, &xfmLeft, &xfmTop) &&
+ FPDF_PageToDevice(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, right, bottom, &xfmRight, &xfmBottom) )
+ return QRectF(xfmLeft, xfmTop, xfmRight - xfmLeft, xfmBottom - xfmTop);
+ return {};
+}
+
+/*! \internal
+ Convert the point \a x , \a y \a from the usual 1x (pixels = points)
+ 4th-quadrant "view" coordinate system relative to the top-left corner of
+ the rendered page, to "page coordinates" suited to the given \a pdfPage,
+ which may have arbitrary internal transforms.
+ */
+QPointF QPdfDocumentPrivate::mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const
+{
+ const auto pageHeight = FPDF_GetPageHeight(pdfPage);
+ const auto pageWidth = FPDF_GetPageWidth(pdfPage);
+ double rx, ry;
+ if (FPDF_DeviceToPage(pdfPage, 0, 0, qRound(pageWidth), qRound(pageHeight), 0, position.x(), position.y(), &rx, &ry))
+ return QPointF(rx, ry);
+ return {};
}
QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF position)
@@ -454,14 +530,14 @@ QPdfDocumentPrivate::TextPosition QPdfDocumentPrivate::hitTest(int page, QPointF
TextPosition result;
FPDF_PAGE pdfPage = FPDF_LoadPage(doc, page);
- double pageHeight = FPDF_GetPageHeight(pdfPage);
FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
- int hitIndex = FPDFText_GetCharIndexAtPos(textPage, position.x(), pageHeight - position.y(),
+ const QPointF pagePos = mapViewToPage(pdfPage, position);
+ int hitIndex = FPDFText_GetCharIndexAtPos(textPage, pagePos.x(), pagePos.y(),
CharacterHitTolerance, CharacterHitTolerance);
if (hitIndex >= 0) {
- QPointF charPos = getCharPosition(textPage, pageHeight, hitIndex);
+ QPointF charPos = getCharPosition(pdfPage, textPage, hitIndex);
if (!charPos.isNull()) {
- QRectF charBox = getCharBox(textPage, pageHeight, hitIndex);
+ QRectF charBox = getCharBox(pdfPage, textPage, hitIndex);
// If the given position is past the end of the line, i.e. if the right edge of the found character's
// bounding box is closer to it than the left edge is, we say that we "hit" the next character index after
if (qAbs(charBox.right() - position.x()) < qAbs(charPos.x() - position.x())) {
@@ -783,6 +859,8 @@ QAbstractListModel *QPdfDocument::pageModel()
If the document does not have custom page numbering, this function returns
\c {page + 1}.
+
+ \sa pageIndexForLabel()
*/
QString QPdfDocument::pageLabel(int page)
{
@@ -797,6 +875,21 @@ QString QPdfDocument::pageLabel(int page)
}
/*!
+ Returns the index of the page that has the \a label, or \c -1 if not found.
+
+ \sa pageLabel()
+ \since 6.6
+*/
+int QPdfDocument::pageIndexForLabel(const QString &label)
+{
+ for (int i = 0; i < d->pageCount; ++i) {
+ if (pageLabel(i) == label)
+ return i;
+ }
+ return -1;
+}
+
+/*!
Renders the \a page into a QImage of size \a imageSize according to the
provided \a renderOptions.
@@ -824,22 +917,6 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions
result.fill(Qt::transparent);
FPDF_BITMAP bitmap = FPDFBitmap_CreateEx(result.width(), result.height(), FPDFBitmap_BGRA, result.bits(), result.bytesPerLine());
- int rotation = 0;
- switch (renderOptions.rotation()) {
- case QPdfDocumentRenderOptions::Rotation::None:
- rotation = 0;
- break;
- case QPdfDocumentRenderOptions::Rotation::Clockwise90:
- rotation = 1;
- break;
- case QPdfDocumentRenderOptions::Rotation::Clockwise180:
- rotation = 2;
- break;
- case QPdfDocumentRenderOptions::Rotation::Clockwise270:
- rotation = 3;
- break;
- }
-
const QPdfDocumentRenderOptions::RenderFlags renderFlags = renderOptions.renderFlags();
int flags = 0;
if (renderFlags & QPdfDocumentRenderOptions::RenderFlag::Annotations)
@@ -885,6 +962,7 @@ QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions
qCDebug(qLcDoc) << "page" << page << "region" << renderOptions.scaledClipRect()
<< "size" << imageSize << "took" << timer.elapsed() << "ms";
} else {
+ const auto rotation = QPdfDocumentPrivate::toFPDFRotation(renderOptions.rotation());
FPDF_RenderPageBitmap(bitmap, pdfPage, 0, 0, result.width(), result.height(), rotation, flags);
qCDebug(qLcDoc) << "page" << page << "size" << imageSize << "took" << timer.elapsed() << "ms";
}
@@ -903,11 +981,12 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end)
{
const QPdfMutexLocker lock;
FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page);
- double pageHeight = FPDF_GetPageHeight(pdfPage);
+ const QPointF pageStart = d->mapViewToPage(pdfPage, start);
+ const QPointF pageEnd = d->mapViewToPage(pdfPage, end);
FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
- int startIndex = FPDFText_GetCharIndexAtPos(textPage, start.x(), pageHeight - start.y(),
+ int startIndex = FPDFText_GetCharIndexAtPos(textPage, pageStart.x(), pageStart.y(),
CharacterHitTolerance, CharacterHitTolerance);
- int endIndex = FPDFText_GetCharIndexAtPos(textPage, end.x(), pageHeight - end.y(),
+ int endIndex = FPDFText_GetCharIndexAtPos(textPage, pageEnd.x(), pageEnd.y(),
CharacterHitTolerance, CharacterHitTolerance);
QPdfSelection result;
@@ -918,7 +997,7 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end)
// If the given end position is past the end of the line, i.e. if the right edge of the last character's
// bounding box is closer to it than the left edge is, then extend the char range by one
- QRectF endCharBox = d->getCharBox(textPage, pageHeight, endIndex);
+ QRectF endCharBox = d->getCharBox(pdfPage, textPage, endIndex);
if (qAbs(endCharBox.right() - end.x()) < qAbs(endCharBox.x() - end.x()))
++endIndex;
@@ -930,7 +1009,7 @@ QPdfSelection QPdfDocument::getSelection(int page, QPointF start, QPointF end)
for (int i = 0; i < rectCount; ++i) {
double l, r, b, t;
FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
- QRectF rect(l, pageHeight - t, r - l, t - b);
+ const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b);
if (hull.isNull())
hull = rect;
else
@@ -960,7 +1039,6 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma
return {};
const QPdfMutexLocker lock;
FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page);
- double pageHeight = FPDF_GetPageHeight(pdfPage);
FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
int pageCount = FPDFText_CountChars(textPage);
if (startIndex >= pageCount)
@@ -975,7 +1053,7 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma
for (int i = 0; i < rectCount; ++i) {
double l, r, b, t;
FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
- QRectF rect(l, pageHeight - t, r - l, t - b);
+ const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b);
if (hull.isNull())
hull = rect;
else
@@ -984,7 +1062,7 @@ QPdfSelection QPdfDocument::getSelectionAtIndex(int page, int startIndex, int ma
}
}
if (bounds.isEmpty())
- hull = QRectF(d->getCharPosition(textPage, pageHeight, startIndex), QSizeF());
+ hull = QRectF(d->getCharPosition(pdfPage, textPage, startIndex), QSizeF());
qCDebug(qLcDoc) << "on page" << page << "at index" << startIndex << "maxLength" << maxLength
<< "got" << text.size() << "chars," << rectCount << "rects within" << hull;
@@ -1001,7 +1079,6 @@ QPdfSelection QPdfDocument::getAllText(int page)
{
const QPdfMutexLocker lock;
FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page);
- double pageHeight = FPDF_GetPageHeight(pdfPage);
FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
int count = FPDFText_CountChars(textPage);
if (count < 1)
@@ -1013,7 +1090,7 @@ QPdfSelection QPdfDocument::getAllText(int page)
for (int i = 0; i < rectCount; ++i) {
double l, r, b, t;
FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
- QRectF rect(l, pageHeight - t, r - l, t - b);
+ const QRectF rect = d->mapPageToView(pdfPage, l, t, r, b);
if (hull.isNull())
hull = rect;
else
diff --git a/src/pdf/qpdfdocument.h b/src/pdf/qpdfdocument.h
index 5f55ed29c..8355246ae 100644
--- a/src/pdf/qpdfdocument.h
+++ b/src/pdf/qpdfdocument.h
@@ -89,6 +89,7 @@ public:
Q_INVOKABLE QSizeF pagePointSize(int page) const;
Q_INVOKABLE QString pageLabel(int page);
+ Q_INVOKABLE int pageIndexForLabel(const QString &label);
QAbstractListModel *pageModel();
diff --git a/src/pdf/qpdfdocument_p.h b/src/pdf/qpdfdocument_p.h
index 973dc1d4a..cdb76d16f 100644
--- a/src/pdf/qpdfdocument_p.h
+++ b/src/pdf/qpdfdocument_p.h
@@ -16,6 +16,7 @@
//
#include "qpdfdocument.h"
+#include "qtpdfexports.h"
#include "third_party/pdfium/public/fpdfview.h"
#include "third_party/pdfium/public/fpdf_dataavail.h"
@@ -37,7 +38,7 @@ public:
class QPdfPageModel;
-class Q_PDF_PRIVATE_EXPORT QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS
+class Q_PDF_EXPORT QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS
{
public:
QPdfDocumentPrivate();
@@ -77,9 +78,37 @@ public:
static int fpdf_GetBlock(void* param, unsigned long position, unsigned char* pBuf, unsigned long size);
static void fpdf_AddSegment(struct _FX_DOWNLOADHINTS* pThis, size_t offset, size_t size);
void updateLastError();
- QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count);
- QPointF getCharPosition(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex);
- QRectF getCharBox(FPDF_TEXTPAGE textPage, double pageHeight, int charIndex);
+ QString getText(FPDF_TEXTPAGE textPage, int startIndex, int count) const;
+ QPointF getCharPosition(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const;
+ QRectF getCharBox(FPDF_PAGE pdfPage, FPDF_TEXTPAGE textPage, int charIndex) const;
+ QPointF mapPageToView(FPDF_PAGE pdfPage, double x, double y) const;
+ QRectF mapPageToView(FPDF_PAGE pdfPage, double left, double top, double right, double bottom) const;
+ QPointF mapViewToPage(FPDF_PAGE pdfPage, QPointF position) const;
+
+ // FPDF takes the rotation parameter as an int.
+ // This enum is mapping the int values defined in fpdfview.h:956.
+ // (not using enum class to ensure int convertability)
+ enum QFPDFRotation {
+ Normal = 0,
+ ClockWise90 = 1,
+ ClockWise180 = 2,
+ CounterClockWise90 = 3
+ };
+
+ static constexpr QFPDFRotation toFPDFRotation(QPdfDocumentRenderOptions::Rotation rotation)
+ {
+ switch (rotation) {
+ case QPdfDocumentRenderOptions::Rotation::None:
+ return QFPDFRotation::Normal;
+ case QPdfDocumentRenderOptions::Rotation::Clockwise90:
+ return QFPDFRotation::ClockWise90;
+ case QPdfDocumentRenderOptions::Rotation::Clockwise180:
+ return QFPDFRotation::ClockWise180;
+ case QPdfDocumentRenderOptions::Rotation::Clockwise270:
+ return QFPDFRotation::CounterClockWise90;
+ }
+ Q_UNREACHABLE();
+ }
struct TextPosition {
QPointF position;
diff --git a/src/pdf/qpdflinkmodel.cpp b/src/pdf/qpdflinkmodel.cpp
index c98a8723e..0a8b1e812 100644
--- a/src/pdf/qpdflinkmodel.cpp
+++ b/src/pdf/qpdflinkmodel.cpp
@@ -2,8 +2,8 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qpdflink_p.h"
+#include "qpdflinkmodel.h"
#include "qpdflinkmodel_p.h"
-#include "qpdflinkmodel_p_p.h"
#include "qpdfdocument_p.h"
#include "third_party/pdfium/public/fpdf_doc.h"
@@ -16,9 +16,9 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
-/*! \internal
+/*!
\class QPdfLinkModel
- \since 5.15
+ \since 6.6
\inmodule QtPdf
\inherits QAbstractListModel
@@ -28,7 +28,7 @@ Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
This is used in PDF viewers to implement the hyperlink mechanism.
*/
-/*! \internal
+/*!
\enum QPdfLinkModel::Role
\value Link A QPdfLink object.
@@ -40,28 +40,31 @@ Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
\omitvalue NRoles
*/
-/*! \internal
+/*!
Constructs a new link model with parent object \a parent.
*/
QPdfLinkModel::QPdfLinkModel(QObject *parent)
- : QAbstractListModel(*(new QPdfLinkModelPrivate()), parent)
+ : QAbstractListModel(parent),
+ d_ptr{std::make_unique<QPdfLinkModelPrivate>(this)}
{
+ Q_D(QPdfLinkModel);
QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role"));
for (int r = Qt::UserRole; r < int(Role::NRoles); ++r)
- m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower());
+ d->roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower());
}
-/*! \internal
+/*!
Destroys the model.
*/
QPdfLinkModel::~QPdfLinkModel() {}
QHash<int, QByteArray> QPdfLinkModel::roleNames() const
{
- return m_roleNames;
+ Q_D(const QPdfLinkModel);
+ return d->roleNames;
}
-/*! \internal
+/*!
\reimp
*/
int QPdfLinkModel::rowCount(const QModelIndex &parent) const
@@ -71,7 +74,7 @@ int QPdfLinkModel::rowCount(const QModelIndex &parent) const
return d->links.size();
}
-/*! \internal
+/*!
\reimp
*/
QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const
@@ -99,9 +102,9 @@ QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const
return QVariant();
}
-/*! \internal
+/*!
\property QPdfLinkModel::document
- \brief the document to load links from
+ \brief The document to load links from.
*/
QPdfDocument *QPdfLinkModel::document() const
{
@@ -125,9 +128,9 @@ void QPdfLinkModel::setDocument(QPdfDocument *document)
d->update();
}
-/*! \internal
+/*!
\property QPdfLinkModel::page
- \brief the page to load links from
+ \brief The page to load links from.
*/
int QPdfLinkModel::page() const
{
@@ -146,8 +149,22 @@ void QPdfLinkModel::setPage(int page)
d->update();
}
-QPdfLinkModelPrivate::QPdfLinkModelPrivate() : QAbstractItemModelPrivate()
+/*!
+ Returns a \l {QPdfLink::isValid()}{valid} link if found under the \a point
+ (given in units of points, 1/72 of an inch), or an invalid link if it is
+ not found. In other words, this function is useful for picking, to handle
+ mouse click or hover.
+*/
+QPdfLink QPdfLinkModel::linkAt(QPointF point) const
{
+ Q_D(const QPdfLinkModel);
+ for (const auto &link : std::as_const(d->links)) {
+ for (const auto &rect : link.rectangles()) {
+ if (rect.contains(point))
+ return link;
+ }
+ }
+ return {};
}
void QPdfLinkModelPrivate::update()
@@ -162,7 +179,6 @@ void QPdfLinkModelPrivate::update()
qCWarning(qLcLink) << "failed to load page" << page;
return;
}
- double pageHeight = FPDF_GetPageHeight(pdfPage);
q->beginResetModel();
links.clear();
@@ -187,8 +203,28 @@ void QPdfLinkModelPrivate::update()
std::swap(rect.bottom, rect.top);
QPdfLink linkData;
- linkData.d->rects << QRectF(rect.left, pageHeight - rect.top,
- rect.right - rect.left, rect.top - rect.bottom);
+ // Use quad points if present; otherwise use the rect.
+ if (int quadPointsCount = FPDFLink_CountQuadPoints(linkAnnot) > 0) {
+ for (int i = 0; i < quadPointsCount; ++i) {
+ FS_QUADPOINTSF point;
+ if (FPDFLink_GetQuadPoints(linkAnnot, i, &point)) {
+ // Quadpoints are counter clockwise from bottom left (x1, y1)
+ QPolygonF poly;
+ poly << QPointF(point.x1, point.y1);
+ poly << QPointF(point.x2, point.y2);
+ poly << QPointF(point.x3, point.y3);
+ poly << QPointF(point.x4, point.y4);
+ QRectF bounds = poly.boundingRect();
+ bounds = document->d->mapPageToView(pdfPage, bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
+ qCDebug(qLcLink) << "quadpoints" << i << "of" << quadPointsCount << ":" << poly << "mapped bounds" << bounds;
+ linkData.d->rects << bounds;
+ // QPdfLink could store polygons rather than rects, to get the benefit of quadpoints;
+ // so far we didn't bother. It would be an API change, and we'd need to use Shapes in PdfLinkDelegate.qml
+ }
+ }
+ } else {
+ linkData.d->rects << document->d->mapPageToView(pdfPage, rect.left, rect.top, rect.right, rect.bottom);
+ }
FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot);
FPDF_ACTION action = FPDFLink_GetAction(linkAnnot);
switch (FPDFAction_GetType(action)) {
@@ -196,7 +232,7 @@ void QPdfLinkModelPrivate::update()
case PDFACTION_GOTO: {
linkData.d->page = FPDFDest_GetDestPageIndex(doc, dest);
if (linkData.d->page < 0) {
- qCWarning(qLcLink) << "skipping link with invalid page number";
+ qCWarning(qLcLink) << "skipping link with invalid page number" << linkData.d->page;
continue; // while enumerating links
}
FPDF_BOOL hasX, hasY, hasZoom;
@@ -207,7 +243,7 @@ void QPdfLinkModelPrivate::update()
break; // at least we got a page number, so the link will jump there
}
if (hasX && hasY)
- linkData.d->location = QPointF(x, pageHeight - y);
+ linkData.d->location = document->d->mapPageToView(pdfPage, x, y);
if (hasZoom)
linkData.d->zoom = zoom;
break;
@@ -270,7 +306,7 @@ void QPdfLinkModelPrivate::update()
double left, top, right, bottom;
bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom);
if (success) {
- linkData.d->rects << QRectF(left, pageHeight - top, right - left, top - bottom);
+ linkData.d->rects << document->d->mapPageToView(pdfPage, left, top, right, bottom);
links << linkData;
}
}
diff --git a/src/pdf/qpdflinkmodel.h b/src/pdf/qpdflinkmodel.h
new file mode 100644
index 000000000..be2ce890c
--- /dev/null
+++ b/src/pdf/qpdflinkmodel.h
@@ -0,0 +1,67 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPDFLINKMODEL_H
+#define QPDFLINKMODEL_H
+
+#include <QtPdf/qtpdfglobal.h>
+#include <QtPdf/qpdfdocument.h>
+#include <QtPdf/qpdflink.h>
+
+#include <QtCore/QAbstractListModel>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfLinkModelPrivate;
+
+class Q_PDF_EXPORT QPdfLinkModel : public QAbstractListModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
+
+public:
+ enum class Role {
+ Link = Qt::UserRole,
+ Rectangle,
+ Url,
+ Page,
+ Location,
+ Zoom,
+ NRoles
+ };
+ Q_ENUM(Role)
+ explicit QPdfLinkModel(QObject *parent = nullptr);
+ ~QPdfLinkModel() override;
+
+ QPdfDocument *document() const;
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+ int page() const;
+
+ QPdfLink linkAt(QPointF point) const;
+
+public Q_SLOTS:
+ void setDocument(QPdfDocument *document);
+ void setPage(int page);
+
+Q_SIGNALS:
+ void documentChanged();
+ void pageChanged(int page);
+
+private Q_SLOTS:
+ void onStatusChanged(QPdfDocument::Status status);
+
+private:
+ Q_DECLARE_PRIVATE(QPdfLinkModel)
+ const std::unique_ptr<QPdfLinkModelPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFLINKMODEL_H
diff --git a/src/pdf/qpdflinkmodel_p.h b/src/pdf/qpdflinkmodel_p.h
index 3251d4e9a..ba46a6e00 100644
--- a/src/pdf/qpdflinkmodel_p.h
+++ b/src/pdf/qpdflinkmodel_p.h
@@ -15,58 +15,26 @@
// We mean it.
//
-#include "qtpdfglobal.h"
-#include "qpdfdocument.h"
-
-#include <QObject>
-#include <QAbstractListModel>
+#include "qpdflinkmodel.h"
+#include <private/qabstractitemmodel_p.h>
QT_BEGIN_NAMESPACE
-class QPdfLinkModelPrivate;
-
-class Q_PDF_EXPORT QPdfLinkModel : public QAbstractListModel
+class QPdfLinkModelPrivate
{
- Q_OBJECT
- Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged)
- Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
+ QPdfLinkModel *q_ptr;
+ Q_DECLARE_PUBLIC(QPdfLinkModel)
public:
- enum class Role : int {
- Link = Qt::UserRole,
- Rectangle,
- Url,
- Page,
- Location,
- Zoom,
- NRoles
- };
- Q_ENUM(Role)
- explicit QPdfLinkModel(QObject *parent = nullptr);
- ~QPdfLinkModel();
-
- QPdfDocument *document() const;
-
- QHash<int, QByteArray> roleNames() const override;
- int rowCount(const QModelIndex &parent) const override;
- QVariant data(const QModelIndex &index, int role) const override;
-
- int page() const;
-
-public Q_SLOTS:
- void setDocument(QPdfDocument *document);
- void setPage(int page);
-
-Q_SIGNALS:
- void documentChanged();
- void pageChanged(int page);
+ explicit QPdfLinkModelPrivate(QPdfLinkModel *qq)
+ : q_ptr(qq) {}
-private Q_SLOTS:
- void onStatusChanged(QPdfDocument::Status status);
+ void update();
-private:
- QHash<int, QByteArray> m_roleNames;
- Q_DECLARE_PRIVATE(QPdfLinkModel)
+ QHash<int, QByteArray> roleNames;
+ QPdfDocument *document = nullptr;
+ QList<QPdfLink> links;
+ int page = 0;
};
QT_END_NAMESPACE
diff --git a/src/pdf/qpdflinkmodel_p_p.h b/src/pdf/qpdflinkmodel_p_p.h
deleted file mode 100644
index ba553d41f..000000000
--- a/src/pdf/qpdflinkmodel_p_p.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (C) 2020 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#ifndef QPDFLINKMODEL_P_P_H
-#define QPDFLINKMODEL_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 "qpdflinkmodel_p.h"
-#include "qpdflink.h"
-#include <private/qabstractitemmodel_p.h>
-
-#include "third_party/pdfium/public/fpdfview.h"
-
-#include <QUrl>
-
-QT_BEGIN_NAMESPACE
-
-class QPdfLinkModelPrivate: public QAbstractItemModelPrivate
-{
- Q_DECLARE_PUBLIC(QPdfLinkModel)
-
-public:
- QPdfLinkModelPrivate();
-
- void update();
-
- QPdfDocument *document = nullptr;
- QList<QPdfLink> links;
- int page = 0;
-};
-
-QT_END_NAMESPACE
-
-#endif // QPDFLINKMODEL_P_P_H
diff --git a/src/pdf/qpdfpagenavigator.cpp b/src/pdf/qpdfpagenavigator.cpp
index 253c1dff8..e077e2184 100644
--- a/src/pdf/qpdfpagenavigator.cpp
+++ b/src/pdf/qpdfpagenavigator.cpp
@@ -207,9 +207,9 @@ void QPdfPageNavigator::jump(QPdfLink destination)
emit currentLocationChanged(currentLocation());
if (d->changing)
return;
- if (!backAvailableWas)
+ if (backAvailableWas != backAvailable())
emit backAvailableChanged(backAvailable());
- if (forwardAvailableWas)
+ if (forwardAvailableWas != forwardAvailable())
emit forwardAvailableChanged(forwardAvailable());
emit jumped(currentLink());
qCDebug(qLcNav) << "push: index" << d->currentHistoryIndex << destination << "-> history" <<
@@ -263,9 +263,9 @@ void QPdfPageNavigator::jump(int page, const QPointF &location, qreal zoom)
emit currentLocationChanged(currentLocation());
if (d->changing)
return;
- if (!backAvailableWas)
+ if (backAvailableWas != backAvailable())
emit backAvailableChanged(backAvailable());
- if (forwardAvailableWas)
+ if (forwardAvailableWas != forwardAvailable())
emit forwardAvailableChanged(forwardAvailable());
emit jumped(currentLink());
qCDebug(qLcNav) << "push: index" << d->currentHistoryIndex << "page" << page
diff --git a/src/pdf/qpdfsearchmodel.cpp b/src/pdf/qpdfsearchmodel.cpp
index a8946ccfe..a81ae77dc 100644
--- a/src/pdf/qpdfsearchmodel.cpp
+++ b/src/pdf/qpdfsearchmodel.cpp
@@ -3,12 +3,11 @@
#include "qpdfdocument_p.h"
#include "qpdflink.h"
-#include "qpdflink_p.h"
#include "qpdfsearchmodel.h"
#include "qpdfsearchmodel_p.h"
-#include "third_party/pdfium/public/fpdf_doc.h"
#include "third_party/pdfium/public/fpdf_text.h"
+#include "third_party/pdfium/public/fpdfview.h"
#include <QtCore/qelapsedtimer.h>
#include <QtCore/qloggingcategory.h>
@@ -20,7 +19,6 @@ Q_LOGGING_CATEGORY(qLcS, "qt.pdf.search")
static const int UpdateTimerInterval = 100;
static const int ContextChars = 64;
-static const double CharacterHitTolerance = 6.0;
/*!
\class QPdfSearchModel
@@ -66,6 +64,10 @@ QPdfSearchModel::QPdfSearchModel(QObject *parent)
roleName[0] = QChar::toLower(roleName[0]);
m_roleNames.insert(r, roleName);
}
+ connect(this, &QAbstractListModel::dataChanged, this, &QPdfSearchModel::countChanged);
+ connect(this, &QAbstractListModel::modelReset, this, &QPdfSearchModel::countChanged);
+ connect(this, &QAbstractListModel::rowsRemoved, this, &QPdfSearchModel::countChanged);
+ connect(this, &QAbstractListModel::rowsInserted, this, &QPdfSearchModel::countChanged);
}
/*!
@@ -125,6 +127,16 @@ QVariant QPdfSearchModel::data(const QModelIndex &index, int role) const
return QVariant();
}
+/*!
+ \since 6.8
+ \property QPdfSearchModel::count
+ \brief the number of search results found
+*/
+int QPdfSearchModel::count() const
+{
+ return rowCount(QModelIndex());
+}
+
void QPdfSearchModel::updatePage(int page)
{
Q_D(QPdfSearchModel);
@@ -174,7 +186,7 @@ QPdfLink QPdfSearchModel::resultAtIndex(int index) const
{
Q_D(const QPdfSearchModel);
const auto pi = const_cast<QPdfSearchModelPrivate*>(d)->pageAndIndexForResult(index);
- if (pi.page < 0)
+ if (pi.page < 0 || index < 0)
return {};
return d->searchResults[pi.page][pi.index];
}
@@ -195,6 +207,10 @@ void QPdfSearchModel::setDocument(QPdfDocument *document)
if (d->document == document)
return;
+ disconnect(d->documentConnection);
+ d->documentConnection = connect(document, &QPdfDocument::pageCountChanged, this,
+ [this]() { d_func()->clearResults(); });
+
d->document = document;
d->clearResults();
emit documentChanged();
@@ -248,7 +264,6 @@ bool QPdfSearchModelPrivate::doSearch(int page)
qWarning() << "failed to load page" << page;
return false;
}
- double pageHeight = FPDF_GetPageHeight(pdfPage);
FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
if (!textPage) {
qWarning() << "failed to load text of page" << page;
@@ -257,6 +272,7 @@ bool QPdfSearchModelPrivate::doSearch(int page)
}
FPDF_SCHHANDLE sh = FPDFText_FindStart(textPage, searchString.utf16(), 0, 0);
QList<QPdfLink> newSearchResults;
+ constexpr double CharacterHitTolerance = 6.0;
while (FPDFText_FindNext(sh)) {
int idx = FPDFText_GetSchResultIndex(sh);
int count = FPDFText_GetSchCount(sh);
@@ -265,9 +281,12 @@ bool QPdfSearchModelPrivate::doSearch(int page)
int startIndex = -1;
int endIndex = -1;
for (int r = 0; r < rectCount; ++r) {
+ // get bounding box of search result in page coordinates
double left, top, right, bottom;
FPDFText_GetRect(textPage, r, &left, &top, &right, &bottom);
- rects << QRectF(left, pageHeight - top, right - left, top - bottom);
+ // deal with any internal PDF transforms and
+ // convert to the 1x (pixels = points) 4th-quadrant coordinate system
+ rects << document->d->mapPageToView(pdfPage, left, top, right, bottom);
if (r == 0) {
startIndex = FPDFText_GetCharIndexAtPos(textPage, left, top,
CharacterHitTolerance, CharacterHitTolerance);
@@ -276,7 +295,8 @@ bool QPdfSearchModelPrivate::doSearch(int page)
endIndex = FPDFText_GetCharIndexAtPos(textPage, right, top,
CharacterHitTolerance, CharacterHitTolerance);
}
- qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex;
+ qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex
+ << "from page rect" << left << top << right << bottom;
}
QString contextBefore, contextAfter;
if (startIndex >= 0 || endIndex >= 0) {
diff --git a/src/pdf/qpdfsearchmodel.h b/src/pdf/qpdfsearchmodel.h
index c1e4e64ec..04f8b9140 100644
--- a/src/pdf/qpdfsearchmodel.h
+++ b/src/pdf/qpdfsearchmodel.h
@@ -19,6 +19,7 @@ class Q_PDF_EXPORT QPdfSearchModel : public QAbstractListModel
Q_OBJECT
Q_PROPERTY(QPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged)
Q_PROPERTY(QString searchString READ searchString WRITE setSearchString NOTIFY searchStringChanged)
+ Q_PROPERTY(int count READ count NOTIFY countChanged REVISION(6, 8) FINAL)
public:
enum class Role : int {
@@ -44,6 +45,8 @@ public:
int rowCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
+ int count() const;
+
public Q_SLOTS:
void setSearchString(const QString &searchString);
void setDocument(QPdfDocument *document);
@@ -51,6 +54,7 @@ public Q_SLOTS:
Q_SIGNALS:
void documentChanged();
void searchStringChanged();
+ Q_REVISION(6, 8) void countChanged();
protected:
void updatePage(int page);
diff --git a/src/pdf/qpdfsearchmodel_p.h b/src/pdf/qpdfsearchmodel_p.h
index 4922c81e9..5ffa08f5d 100644
--- a/src/pdf/qpdfsearchmodel_p.h
+++ b/src/pdf/qpdfsearchmodel_p.h
@@ -45,6 +45,8 @@ public:
int rowCountSoFar = 0;
int updateTimerId = -1;
int nextPageToUpdate = 0;
+
+ QMetaObject::Connection documentConnection;
};
QT_END_NAMESPACE
diff --git a/src/pdf/qtpdfglobal.h b/src/pdf/qtpdfglobal.h
index d38eafaab..2d0900029 100644
--- a/src/pdf/qtpdfglobal.h
+++ b/src/pdf/qtpdfglobal.h
@@ -5,24 +5,7 @@
#define QTPDFGLOBAL_H
#include <QtCore/qglobal.h>
-
-QT_BEGIN_NAMESPACE
-
-#ifndef Q_PDF_EXPORT
-# ifndef QT_STATIC
-# if defined(QT_BUILD_PDF_LIB)
-# define Q_PDF_EXPORT Q_DECL_EXPORT
-# else
-# define Q_PDF_EXPORT Q_DECL_IMPORT
-# endif
-# else
-# define Q_PDF_EXPORT
-# endif
-#endif
-
-#define Q_PDF_PRIVATE_EXPORT Q_PDF_EXPORT
-
-QT_END_NAMESPACE
+#include <QtPdf/qtpdfexports.h>
#endif // QTPDFGLOBAL_H
diff --git a/src/pdfquick/+Material/PdfStyle.qml b/src/pdfquick/+Material/PdfStyle.qml
index f67b49646..0728616a2 100644
--- a/src/pdfquick/+Material/PdfStyle.qml
+++ b/src/pdfquick/+Material/PdfStyle.qml
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
import QtQuick
import QtQuick.Controls.Material
-import QtQuick.Shapes
QtObject {
property SystemPalette palette: SystemPalette { }
diff --git a/src/pdfquick/+Universal/PdfStyle.qml b/src/pdfquick/+Universal/PdfStyle.qml
index 2d1c5e1d1..4c559f068 100644
--- a/src/pdfquick/+Universal/PdfStyle.qml
+++ b/src/pdfquick/+Universal/PdfStyle.qml
@@ -2,7 +2,6 @@
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
import QtQuick
import QtQuick.Controls.Universal
-import QtQuick.Shapes
QtObject {
property SystemPalette palette: SystemPalette { }
diff --git a/src/pdfquick/CMakeLists.txt b/src/pdfquick/CMakeLists.txt
index 560817446..d57ce04aa 100644
--- a/src/pdfquick/CMakeLists.txt
+++ b/src/pdfquick/CMakeLists.txt
@@ -36,5 +36,6 @@ qt_internal_add_qml_module(PdfQuick
Qt::Core
Qt::Gui
Qt::Qml
+ NO_GENERATE_CPP_EXPORTS
)
diff --git a/src/pdfquick/PdfLinkDelegate.qml b/src/pdfquick/PdfLinkDelegate.qml
index aba86d61d..4ac54d161 100644
--- a/src/pdfquick/PdfLinkDelegate.qml
+++ b/src/pdfquick/PdfLinkDelegate.qml
@@ -50,24 +50,25 @@ Item {
}
TapHandler {
gesturePolicy: TapHandler.ReleaseWithinBounds
- onTapped: root.tapped(link)
+ onTapped: root.tapped(root.link)
}
TapHandler {
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad | PointerDevice.Stylus
acceptedButtons: Qt.RightButton
gesturePolicy: TapHandler.ReleaseWithinBounds
- onTapped: root.contextMenuRequested(link)
+ onTapped: root.contextMenuRequested(root.link)
}
TapHandler {
acceptedDevices: PointerDevice.TouchScreen
- onLongPressed: root.contextMenuRequested(link)
+ onLongPressed: root.contextMenuRequested(root.link)
}
ToolTip {
visible: linkHH.hovered
delay: 1000
property string destFormat: qsTr("Page %1 location %2, %3 zoom %4")
- text: page >= 0 ?
- destFormat.arg(page + 1).arg(location.x.toFixed(1)).arg(location.y.toFixed(1)).arg(zoom) :
- url
+ text: root.page >= 0 ?
+ destFormat.arg(root.page + 1).arg(root.location.x.toFixed(1))
+ .arg(root.location.y.toFixed(1)).arg(root.zoom) :
+ root.url
}
}
diff --git a/src/pdfquick/PdfMultiPageView.qml b/src/pdfquick/PdfMultiPageView.qml
index 0f62a229d..194d7866e 100644
--- a/src/pdfquick/PdfMultiPageView.qml
+++ b/src/pdfquick/PdfMultiPageView.qml
@@ -1,5 +1,8 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
import QtQuick
import QtQuick.Controls
import QtQuick.Pdf
@@ -56,8 +59,8 @@ Item {
*/
function selectAll() {
const currentItem = tableView.itemAtCell(tableView.cellAtPos(root.width / 2, root.height / 2))
- if (currentItem)
- currentItem.selection.selectAll()
+ const pdfSelection = currentItem?.selection as PdfSelection
+ pdfSelection?.selectAll()
}
/*!
@@ -70,9 +73,9 @@ Item {
*/
function copySelectionToClipboard() {
const currentItem = tableView.itemAtCell(tableView.cellAtPos(root.width / 2, root.height / 2))
- console.log(lcMPV, "currentItem", currentItem, "sel", currentItem.selection.text)
- if (currentItem)
- currentItem.selection.copyToClipboard()
+ const pdfSelection = currentItem?.selection as PdfSelection
+ console.log(lcMPV, "currentItem", currentItem, "sel", pdfSelection?.text)
+ pdfSelection?.copyToClipboard()
}
// --------------------------------
@@ -159,6 +162,13 @@ Item {
\sa PdfPageNavigator::jump(), currentPage
*/
function goToLocation(page, location, zoom) {
+ if (tableView.rows === 0) {
+ // save this request for later
+ tableView.pendingRow = page
+ tableView.pendingLocation = location
+ tableView.pendingZoom = zoom
+ return
+ }
if (zoom > 0) {
pageNavigator.jumping = true // don't call pageNavigator.update() because we will jump() instead
root.renderScale = zoom
@@ -298,26 +308,35 @@ Item {
property point jumpLocationMargin: Qt.point(10, 10) // px away from viewport edges
anchors.fill: parent
anchors.leftMargin: 2
- model: modelInUse && root.document ? root.document.pageCount : 0
- // workaround to make TableView do scheduleRebuildTable(RebuildOption::All) in cases when forceLayout() doesn't
- property bool modelInUse: true
- function rebuild() {
- modelInUse = false
- modelInUse = true
- }
- // end workaround
+ model: root.document ? root.document.pageCount : 0
rowSpacing: 6
property real rotationNorm: Math.round((360 + (root.pageRotation % 360)) % 360)
property bool rot90: rotationNorm == 90 || rotationNorm == 270
onRot90Changed: forceLayout()
onHeightChanged: forceLayout()
onWidthChanged: forceLayout()
- property size firstPagePointSize: document?.status === PdfDocument.Ready ? document.pagePointSize(0) : Qt.size(1, 1)
- property real pageHolderWidth: Math.max(root.width, ((rot90 ? document?.maxPageHeight : document?.maxPageWidth) ?? 0) * root.renderScale)
- columnWidthProvider: function(col) { return document ? pageHolderWidth + vscroll.width + 2 : 0 }
- rowHeightProvider: function(row) { return (rot90 ? document.pagePointSize(row).width : document.pagePointSize(row).height) * root.renderScale }
+ property size firstPagePointSize: root.document?.status === PdfDocument.Ready ? root.document.pagePointSize(0) : Qt.size(1, 1)
+ property real pageHolderWidth: Math.max(root.width, ((rot90 ? root.document?.maxPageHeight : root.document?.maxPageWidth) ?? 0) * root.renderScale)
+ columnWidthProvider: function(col) { return root.document ? pageHolderWidth + vscroll.width + 2 : 0 }
+ rowHeightProvider: function(row) { return (rot90 ? root.document.pagePointSize(row).width : root.document.pagePointSize(row).height) * root.renderScale }
+
+ // delayed-jump feature in case the user called goToPage() or goToLocation() too early
+ property int pendingRow: -1
+ property point pendingLocation
+ property real pendingZoom: -1
+ onRowsChanged: {
+ if (rows > 0 && tableView.pendingRow >= 0) {
+ console.log(lcMPV, "initiating delayed jump to page", tableView.pendingRow, "loc", tableView.pendingLocation, "zoom", tableView.pendingZoom)
+ root.goToLocation(tableView.pendingRow, tableView.pendingLocation, tableView.pendingZoom)
+ tableView.pendingRow = -1
+ tableView.pendingLocation = Qt.point(-1, -1)
+ tableView.pendingZoom = -1
+ }
+ }
+
delegate: Rectangle {
id: pageHolder
+ required property int index
color: tableView.debug ? "beige" : "transparent"
Text {
visible: tableView.debug
@@ -332,12 +351,12 @@ Item {
height: image.height
rotation: root.pageRotation
anchors.centerIn: pinch.active ? undefined : parent
- property size pagePointSize: document.pagePointSize(index)
+ property size pagePointSize: root.document.pagePointSize(pageHolder.index)
property real pageScale: image.paintedWidth / pagePointSize.width
PdfPageImage {
id: image
document: root.document
- currentFrame: index
+ currentFrame: pageHolder.index
asynchronous: true
fillMode: Image.PreserveAspectFit
width: paper.pagePointSize.width * root.renderScale
@@ -351,7 +370,7 @@ Item {
searchHighlights.update()
}
onStatusChanged: {
- if (index === pageNavigator.currentPage)
+ if (pageHolder.index === pageNavigator.currentPage)
root.currentPageRenderingStatus = status
}
}
@@ -367,7 +386,7 @@ Item {
id: searchHighlights
function update() {
// paths could be a binding, but we need to be able to "kick" it sometimes
- paths = searchModel.boundingPolygonsOnPage(index)
+ paths = searchModel.boundingPolygonsOnPage(pageHolder.index)
}
}
}
@@ -388,7 +407,7 @@ Item {
}
Shape {
anchors.fill: parent
- visible: image.status === Image.Ready && searchModel.currentPage === index
+ visible: image.status === Image.Ready && searchModel.currentPage === pageHolder.index
ShapePath {
strokeWidth: style.currentSearchResultStrokeWidth
strokeColor: style.currentSearchResultStrokeColor
@@ -415,12 +434,16 @@ Item {
const centroidInFlickable = tableView.mapFromItem(paper, pinch.centroid.position.x, pinch.centroid.position.y)
const newSourceWidth = image.sourceSize.width * paper.scale
const ratio = newSourceWidth / image.sourceSize.width
- console.log(lcMPV, "pinch ended on page", index, "with centroid", pinch.centroid.position, centroidInPoints, "wrt flickable", centroidInFlickable,
+ console.log(lcMPV, "pinch ended on page", pageHolder.index,
+ "with scale", paper.scale.toFixed(3), "ratio", ratio.toFixed(3),
+ "centroid", pinch.centroid.position, centroidInPoints,
+ "wrt flickable", centroidInFlickable,
"page at", pageHolder.x.toFixed(2), pageHolder.y.toFixed(2),
"contentX/Y were", tableView.contentX.toFixed(2), tableView.contentY.toFixed(2))
if (ratio > 1.1 || ratio < 0.9) {
const centroidOnPage = Qt.point(centroidInPoints.x * root.renderScale * ratio, centroidInPoints.y * root.renderScale * ratio)
paper.scale = 1
+ pinch.persistentScale = 1
paper.x = 0
paper.y = 0
root.renderScale *= ratio
@@ -528,8 +551,8 @@ Item {
// and don't force layout either, because positionViewAtCell() will do that
if (pageNavigator.jumping)
return
- // make TableView rebuild from scratch, because otherwise it doesn't know the delegates are changing size
- tableView.rebuild()
+ // page size changed: TableView needs to redo layout to avoid overlapping delegates or gaps between them
+ tableView.forceLayout()
const cell = tableView.cellAtPos(root.width / 2, root.height / 2)
const currentItem = tableView.itemAtCell(cell)
if (currentItem) {
diff --git a/src/pdfquick/PdfPageView.qml b/src/pdfquick/PdfPageView.qml
index 8e99ead7e..290570f2b 100644
--- a/src/pdfquick/PdfPageView.qml
+++ b/src/pdfquick/PdfPageView.qml
@@ -1,9 +1,11 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
import QtQuick
import QtQuick.Pdf
import QtQuick.Shapes
-import Qt.labs.animation
/*!
\qmltype PdfPageView
diff --git a/src/pdfquick/PdfScrollablePageView.qml b/src/pdfquick/PdfScrollablePageView.qml
index 5295db7f8..9fa0547c6 100644
--- a/src/pdfquick/PdfScrollablePageView.qml
+++ b/src/pdfquick/PdfScrollablePageView.qml
@@ -1,5 +1,8 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+pragma ComponentBehavior: Bound
+
import QtQuick
import QtQuick.Controls
import QtQuick.Pdf
@@ -302,9 +305,6 @@ Flickable {
}
onRenderScaleChanged: {
- image.sourceSize.width = document.pagePointSize(pageNavigator.currentPage).width *
- renderScale * Screen.devicePixelRatio
- image.sourceSize.height = 0
paper.scale = 1
const currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale,
(root.contentY + root.height / 2) / root.renderScale)
@@ -365,6 +365,10 @@ Flickable {
rotation: root.pageRotation
anchors.centerIn: parent
property real pageScale: image.paintedWidth / document.pagePointSize(pageNavigator.currentPage).width
+ width: document.pagePointSize(pageNavigator.currentPage).width * root.renderScale
+ height: document.pagePointSize(pageNavigator.currentPage).height * root.renderScale
+ sourceSize.width: width * Screen.devicePixelRatio
+ sourceSize.height: 0
Shape {
anchors.fill: parent
diff --git a/src/pdfquick/PdfStyle.qml b/src/pdfquick/PdfStyle.qml
index 8e688e6e2..a22276143 100644
--- a/src/pdfquick/PdfStyle.qml
+++ b/src/pdfquick/PdfStyle.qml
@@ -1,8 +1,6 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
import QtQuick
-import QtQuick.Controls
-import QtQuick.Shapes
/*!
\qmltype PdfStyle
diff --git a/src/pdfquick/doc/src/qtquickpdf-module.qdoc b/src/pdfquick/doc/src/qtquickpdf-module.qdoc
index 1d31f6148..a4ca0d9e8 100644
--- a/src/pdfquick/doc/src/qtquickpdf-module.qdoc
+++ b/src/pdfquick/doc/src/qtquickpdf-module.qdoc
@@ -12,7 +12,7 @@
To use the types in this module, import the module with the following line:
- \code
+ \qml
import QtQuick.Pdf
- \endcode
+ \endqml
*/
diff --git a/src/pdfquick/qquickpdfdocument.cpp b/src/pdfquick/qquickpdfdocument.cpp
index 368725a8e..9770900db 100644
--- a/src/pdfquick/qquickpdfdocument.cpp
+++ b/src/pdfquick/qquickpdfdocument.cpp
@@ -8,6 +8,7 @@
#include <QtQml/qqmlcontext.h>
#include <QtQml/qqmlengine.h>
#include <QtQuick/qquickitem.h>
+#include <QtQml/qqmlfile.h>
QT_BEGIN_NAMESPACE
@@ -35,15 +36,18 @@ QQuickPdfDocument::QQuickPdfDocument(QObject *parent)
/*!
\internal
*/
-QQuickPdfDocument::~QQuickPdfDocument() = default;
+QQuickPdfDocument::~QQuickPdfDocument()
+{
+ delete m_carrierFile;
+};
void QQuickPdfDocument::classBegin()
{
m_doc = static_cast<QPdfDocument *>(qmlExtendedObject(this));
Q_ASSERT(m_doc);
- connect(m_doc, &QPdfDocument::passwordChanged, this, [this]() {
- if (resolvedSource().isValid() && resolvedSource().isLocalFile())
- m_doc->load(resolvedSource().path());
+ connect(m_doc, &QPdfDocument::passwordChanged, this, [this]() -> void {
+ if (resolvedSource().isValid())
+ m_doc->load(QQmlFile::urlToLocalFileOrQrc(resolvedSource()));
});
connect(m_doc, &QPdfDocument::statusChanged, this, [this] (QPdfDocument::Status status) {
emit errorChanged();
@@ -68,15 +72,14 @@ void QQuickPdfDocument::setSource(QUrl source)
m_source = source;
m_maxPageWidthHeight = QSizeF();
- m_carrierFile->deleteLater();
+ if (m_carrierFile)
+ m_carrierFile->deleteLater();
m_carrierFile = nullptr;
emit sourceChanged();
const QQmlContext *context = qmlContext(this);
m_resolvedSource = context ? context->resolvedUrl(source) : source;
- if (source.scheme() == QLatin1String("qrc"))
- m_doc->load(QLatin1Char(':') + m_resolvedSource.path());
- else
- m_doc->load(m_resolvedSource.toLocalFile());
+ if (m_resolvedSource.isValid())
+ m_doc->load(QQmlFile::urlToLocalFileOrQrc(m_resolvedSource));
}
/*!
diff --git a/src/pdfquick/qquickpdfpageimage.cpp b/src/pdfquick/qquickpdfpageimage.cpp
index 2ea8ebc12..f2da067f1 100644
--- a/src/pdfquick/qquickpdfpageimage.cpp
+++ b/src/pdfquick/qquickpdfpageimage.cpp
@@ -76,6 +76,18 @@ QQuickPdfDocument *QQuickPdfPageImage::document() const
void QQuickPdfPageImage::load()
{
Q_D(QQuickPdfPageImage);
+ QUrl url = source();
+ if (!d->doc || !d->doc->carrierFile()) {
+ if (!url.isEmpty()) {
+ qmlWarning(this) << "document property not set: falling back to inefficient loading of " << url;
+ QQuickImageBase::load();
+ }
+ return;
+ }
+ if (url != d->doc->resolvedSource()) {
+ url = d->doc->resolvedSource();
+ qmlWarning(this) << "document and source properties in conflict: preferring document source " << url;
+ }
auto carrierFile = d->doc->carrierFile();
static int thisRequestProgress = -1;
static int thisRequestFinished = -1;
@@ -86,7 +98,7 @@ void QQuickPdfPageImage::load()
QQuickImageBase::staticMetaObject.indexOfSlot("requestFinished()");
}
- d->pix.loadImageFromDevice(qmlEngine(this), carrierFile, d->url,
+ d->pix.loadImageFromDevice(qmlEngine(this), carrierFile, url,
d->sourceClipRect.toRect(), d->sourcesize * d->devicePixelRatio,
QQuickImageProviderOptions(), d->currentFrame, d->frameCount);
diff --git a/src/pdfquick/qquickpdfsearchmodel.cpp b/src/pdfquick/qquickpdfsearchmodel.cpp
index ca33a6dc6..896584ad7 100644
--- a/src/pdfquick/qquickpdfsearchmodel.cpp
+++ b/src/pdfquick/qquickpdfsearchmodel.cpp
@@ -199,7 +199,7 @@ QList<QPolygonF> QQuickPdfSearchModel::boundingPolygonsOnPage(int page)
*/
void QQuickPdfSearchModel::setCurrentPage(int currentPage)
{
- if (m_currentPage == currentPage)
+ if (m_currentPage == currentPage || !document())
return;
const auto pageCount = document()->document()->pageCount();
@@ -270,6 +270,13 @@ QPdfLink QQuickPdfSearchModel::currentResultLink() const
The string to search for.
*/
+/*!
+ \since 6.8
+ \qmlproperty int PdfSearchModel::count
+
+ The number of search results found.
+*/
+
QT_END_NAMESPACE
#include "moc_qquickpdfsearchmodel_p.cpp"
diff --git a/src/pdfwidgets/CMakeLists.txt b/src/pdfwidgets/CMakeLists.txt
index d374315e3..41af017c0 100644
--- a/src/pdfwidgets/CMakeLists.txt
+++ b/src/pdfwidgets/CMakeLists.txt
@@ -5,6 +5,7 @@ find_package(Qt6 ${PROJECT_VERSION} CONFIG REQUIRED COMPONENTS Core Gui Widgets)
qt_internal_add_module(PdfWidgets
SOURCES
+ qpdfpageselector.cpp qpdfpageselector.h qpdfpageselector_p.h
qpdfview.cpp qpdfview.h qpdfview_p.h
qtpdfwidgetsglobal.h
LIBRARIES
@@ -14,4 +15,5 @@ qt_internal_add_module(PdfWidgets
Qt::Gui
Qt::Widgets
Qt::Pdf
+ NO_GENERATE_CPP_EXPORTS
)
diff --git a/src/pdfwidgets/qpdfpageselector.cpp b/src/pdfwidgets/qpdfpageselector.cpp
new file mode 100644
index 000000000..66b781ed3
--- /dev/null
+++ b/src/pdfwidgets/qpdfpageselector.cpp
@@ -0,0 +1,171 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#include "qpdfpageselector.h"
+#include "qpdfpageselector_p.h"
+
+#include <QPdfDocument>
+
+#include <QtWidgets/qboxlayout.h>
+
+using namespace Qt::StringLiterals;
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPdfPageSelector
+ \inmodule QtPdf
+ \since 6.6
+ \brief A widget for selecting a PDF page.
+
+ QPdfPageSelector is a widget for selecting a page label from a
+ QPdfDocument.
+
+ \sa QPdfDocument::pageLabel()
+*/
+
+/*!
+ Constructs a PDF page selector with parent widget \a parent.
+*/
+QPdfPageSelector::QPdfPageSelector(QWidget *parent)
+ : QWidget(parent), d_ptr(new QPdfPageSelectorPrivate)
+{
+ Q_D(QPdfPageSelector);
+ d->spinBox = new QPdfPageSelectorSpinBox(this);
+ d->spinBox->setObjectName(u"_q_spinBox"_s);
+ auto vlay = new QVBoxLayout(this);
+ vlay->setContentsMargins({});
+ vlay->addWidget(d->spinBox);
+
+ connect(d->spinBox, &QPdfPageSelectorSpinBox::_q_documentChanged,
+ this, &QPdfPageSelector::documentChanged);
+ connect(d->spinBox, &QSpinBox::valueChanged, this, &QPdfPageSelector::currentPageChanged);
+ connect(d->spinBox, &QSpinBox::textChanged, this, &QPdfPageSelector::currentPageLabelChanged);
+}
+
+/*!
+ Destroys the page selector.
+*/
+QPdfPageSelector::~QPdfPageSelector()
+ = default;
+
+/*!
+ \property QPdfPageSelector::document
+
+ This property holds the document to be viewed.
+*/
+
+void QPdfPageSelector::setDocument(QPdfDocument *doc)
+{
+ Q_D(QPdfPageSelector);
+ d->spinBox->setDocument(doc);
+}
+
+QPdfDocument *QPdfPageSelector::document() const
+{
+ Q_D(const QPdfPageSelector);
+ return d->spinBox->document();
+}
+
+/*!
+ \property QPdfPageSelector::currentPage
+
+ This property holds the index (\c{0}-based) of the current page in the
+ document.
+*/
+
+int QPdfPageSelector::currentPage() const
+{
+ Q_D(const QPdfPageSelector);
+ return d->spinBox->value();
+}
+
+void QPdfPageSelector::setCurrentPage(int index)
+{
+ Q_D(QPdfPageSelector);
+ d->spinBox->setValue(index);
+}
+
+/*!
+ \property QPdfPageSelector::currentPageLabel
+
+ This property holds the page label corresponding to the current page
+ in the document.
+
+ This is the text presented to the user.
+
+ \sa QPdfDocument::pageLabel()
+*/
+
+QString QPdfPageSelector::currentPageLabel() const
+{
+ Q_D(const QPdfPageSelector);
+ return d->spinBox->text();
+}
+
+//
+// QPdfPageSelectorSpinBox:
+//
+
+void QPdfPageSelectorSpinBox::documentStatusChanged()
+{
+ if (m_document && m_document->status() == QPdfDocument::Status::Ready) {
+ setMaximum(m_document->pageCount());
+ setValue(0);
+ }
+}
+
+void QPdfPageSelectorSpinBox::setDocument(QPdfDocument *document)
+{
+ if (m_document == document)
+ return;
+
+ if (m_document)
+ disconnect(m_documentStatusChangedConnection);
+
+ m_document = document;
+ emit _q_documentChanged(document);
+
+ if (m_document) {
+ m_documentStatusChangedConnection =
+ connect(m_document.get(), &QPdfDocument::statusChanged,
+ this, &QPdfPageSelectorSpinBox::documentStatusChanged);
+ }
+
+ documentStatusChanged();
+}
+
+QPdfPageSelectorSpinBox::QPdfPageSelectorSpinBox(QWidget *parent)
+ : QSpinBox(parent)
+{
+}
+
+QPdfPageSelectorSpinBox::~QPdfPageSelectorSpinBox()
+ = default;
+
+int QPdfPageSelectorSpinBox::valueFromText(const QString &text) const
+{
+ if (!m_document)
+ return 0;
+
+ return m_document->pageIndexForLabel(text.trimmed());
+}
+
+QString QPdfPageSelectorSpinBox::textFromValue(int value) const
+{
+ if (!m_document)
+ return {};
+
+ return m_document->pageLabel(value);
+}
+
+QValidator::State QPdfPageSelectorSpinBox::validate(QString &text, int &pos) const
+{
+ Q_UNUSED(pos);
+ return valueFromText(text) >= 0 ? QValidator::Acceptable : QValidator::Intermediate;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfpageselector_p.cpp"
+#include "moc_qpdfpageselector.cpp"
diff --git a/src/pdfwidgets/qpdfpageselector.h b/src/pdfwidgets/qpdfpageselector.h
new file mode 100644
index 000000000..d779f54cd
--- /dev/null
+++ b/src/pdfwidgets/qpdfpageselector.h
@@ -0,0 +1,51 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPDFPAGESELECTOR_H
+#define QPDFPAGESELECTOR_H
+
+#include <QtPdfWidgets/qtpdfwidgetsglobal.h>
+
+#include <QtWidgets/qwidget.h>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocument;
+class QPdfPageSelectorPrivate;
+
+class Q_PDF_WIDGETS_EXPORT QPdfPageSelector : public QWidget
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged USER true)
+ Q_PROPERTY(QString currentPageLabel READ currentPageLabel NOTIFY currentPageLabelChanged)
+public:
+ QPdfPageSelector() : QPdfPageSelector(nullptr) {}
+ explicit QPdfPageSelector(QWidget *parent);
+ ~QPdfPageSelector() override;
+
+ void setDocument(QPdfDocument *document);
+ QPdfDocument *document() const;
+
+ int currentPage() const;
+ QString currentPageLabel() const;
+
+public Q_SLOTS:
+ void setCurrentPage(int index);
+
+Q_SIGNALS:
+ void documentChanged(QPdfDocument *document);
+ void currentPageChanged(int index);
+ void currentPageLabelChanged(const QString &label);
+
+private:
+ Q_DECLARE_PRIVATE(QPdfPageSelector)
+ const std::unique_ptr<QPdfPageSelectorPrivate> d_ptr;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFPAGESELECTOR_H
diff --git a/src/pdfwidgets/qpdfpageselector_p.h b/src/pdfwidgets/qpdfpageselector_p.h
new file mode 100644
index 000000000..8e961f1d2
--- /dev/null
+++ b/src/pdfwidgets/qpdfpageselector_p.h
@@ -0,0 +1,60 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+#ifndef QPDFPAGESELECTOR_P_H
+#define QPDFPAGESELECTOR_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 "qpdfpageselector.h"
+
+#include <QtWidgets/qspinbox.h>
+
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfPageSelectorSpinBox : public QSpinBox
+{
+ Q_OBJECT
+public:
+ QPdfPageSelectorSpinBox() : QPdfPageSelectorSpinBox(nullptr) {}
+ explicit QPdfPageSelectorSpinBox(QWidget *parent);
+ ~QPdfPageSelectorSpinBox();
+
+ void setDocument(QPdfDocument *document);
+ QPdfDocument *document() const { return m_document.get(); }
+
+Q_SIGNALS:
+ void _q_documentChanged(QPdfDocument *document);
+
+protected:
+ int valueFromText(const QString &text) const override;
+ QString textFromValue(int value) const override;
+ QValidator::State validate(QString &text, int &pos) const override;
+
+private:
+ void documentStatusChanged();
+private:
+ QPointer<QPdfDocument> m_document;
+ QMetaObject::Connection m_documentStatusChangedConnection;
+};
+
+class QPdfPageSelectorPrivate
+{
+public:
+ QPdfPageSelectorSpinBox *spinBox;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFPAGESELECTOR_P_H
diff --git a/src/pdfwidgets/qpdfview.cpp b/src/pdfwidgets/qpdfview.cpp
index 831b51515..a67667fed 100644
--- a/src/pdfwidgets/qpdfview.cpp
+++ b/src/pdfwidgets/qpdfview.cpp
@@ -8,16 +8,24 @@
#include "qpdfpagerenderer.h"
#include <QGuiApplication>
+#include <QLoggingCategory>
#include <QPainter>
#include <QPaintEvent>
#include <QPdfDocument>
#include <QPdfPageNavigator>
+#include <QPdfSearchModel>
#include <QScreen>
#include <QScrollBar>
-#include <QScroller>
QT_BEGIN_NAMESPACE
+Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
+//#define DEBUG_LINKS
+
+static const QColor SearchResultHighlight("#80B0C4DE");
+static const QColor CurrentSearchResultHighlight(Qt::cyan);
+static const int CurrentSearchResultWidth(2);
+
QPdfViewPrivate::QPdfViewPrivate(QPdfView *q)
: q_ptr(q)
, m_document(nullptr)
@@ -98,8 +106,9 @@ void QPdfViewPrivate::setViewport(QRect viewport)
const QRect currentPageLine(m_viewport.x(), m_viewport.y() + m_viewport.height() * 0.4, m_viewport.width(), 2);
int currentPage = 0;
- for (auto it = m_documentLayout.pageGeometries.cbegin(); it != m_documentLayout.pageGeometries.cend(); ++it) {
- const QRect pageGeometry = it.value();
+ for (auto it = m_documentLayout.pageGeometryAndScale.cbegin();
+ it != m_documentLayout.pageGeometryAndScale.cend(); ++it) {
+ const QRect pageGeometry = it.value().first;
if (pageGeometry.intersects(currentPageLine)) {
currentPage = it.key();
break;
@@ -174,7 +183,7 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const
if (!m_document || m_document->status() != QPdfDocument::Status::Ready)
return documentLayout;
- QHash<int, QRect> pageGeometries;
+ QHash<int, QPair<QRect, qreal>> pageGeometryAndScale;
const int pageCount = m_document->pageCount();
@@ -186,24 +195,28 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const
// calculate page sizes
for (int page = startPage; page < endPage; ++page) {
QSize pageSize;
+ qreal pageScale = m_zoomFactor;
if (m_zoomMode == QPdfView::ZoomMode::Custom) {
pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution * m_zoomFactor).toSize();
} else if (m_zoomMode == QPdfView::ZoomMode::FitToWidth) {
pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution).toSize();
- const qreal factor = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) /
- qreal(pageSize.width()));
- pageSize *= factor;
+ pageScale = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) /
+ qreal(pageSize.width()));
+ pageSize *= pageScale;
} else if (m_zoomMode == QPdfView::ZoomMode::FitInView) {
const QSize viewportSize(m_viewport.size() +
QSize(-m_documentMargins.left() - m_documentMargins.right(), -m_pageSpacing));
pageSize = QSizeF(m_document->pagePointSize(page) * m_screenResolution).toSize();
- pageSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio);
+ QSize scaledSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio);
+ // because of KeepAspectRatio, the ratio of widths should be the same as the ratio of heights
+ pageScale = qreal(scaledSize.width()) / qreal(pageSize.width());
+ pageSize = scaledSize;
}
totalWidth = qMax(totalWidth, pageSize.width());
- pageGeometries[page] = QRect(QPoint(0, 0), pageSize);
+ pageGeometryAndScale[page] = {QRect(QPoint(0, 0), pageSize), pageScale};
}
totalWidth += m_documentMargins.left() + m_documentMargins.right();
@@ -212,19 +225,19 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const
// calculate page positions
for (int page = startPage; page < endPage; ++page) {
- const QSize pageSize = pageGeometries[page].size();
+ const QSize pageSize = pageGeometryAndScale[page].first.size();
// center horizontal inside the viewport
const int pageX = (qMax(totalWidth, m_viewport.width()) - pageSize.width()) / 2;
- pageGeometries[page].moveTopLeft(QPoint(pageX, pageY));
+ pageGeometryAndScale[page].first.moveTopLeft(QPoint(pageX, pageY));
pageY += pageSize.height() + m_pageSpacing;
}
pageY += m_documentMargins.bottom();
- documentLayout.pageGeometries = pageGeometries;
+ documentLayout.pageGeometryAndScale = pageGeometryAndScale;
// calculate overall document size
documentLayout.documentSize = QSize(totalWidth, pageY);
@@ -234,11 +247,26 @@ QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const
qreal QPdfViewPrivate::yPositionForPage(int pageNumber) const
{
- const auto it = m_documentLayout.pageGeometries.constFind(pageNumber);
- if (it == m_documentLayout.pageGeometries.cend())
+ const auto it = m_documentLayout.pageGeometryAndScale.constFind(pageNumber);
+ if (it == m_documentLayout.pageGeometryAndScale.cend())
return 0.0;
- return (*it).y();
+ return (*it).first.y();
+}
+
+QTransform QPdfViewPrivate::screenScaleTransform(int page) const
+{
+ qreal scale = m_screenResolution * m_zoomFactor;
+ switch (m_zoomMode) {
+ case QPdfView::ZoomMode::FitToWidth:
+ case QPdfView::ZoomMode::FitInView:
+ scale = m_screenResolution * m_documentLayout.pageGeometryAndScale[page].second;
+ break;
+ default:
+ break;
+ }
+
+ return QTransform::fromScale(scale, scale);
}
void QPdfViewPrivate::updateDocumentLayout()
@@ -281,8 +309,7 @@ QPdfView::QPdfView(QWidget *parent)
verticalScrollBar()->setSingleStep(20);
horizontalScrollBar()->setSingleStep(20);
- QScroller::grabGesture(this);
-
+ setMouseTracking(true);
d->calculateViewport();
}
@@ -317,6 +344,7 @@ void QPdfView::setDocument(QPdfDocument *document)
[d](){ d->documentStatusChanged(); });
d->m_pageRenderer->setDocument(d->m_document);
+ d->m_linkModel.setDocument(d->m_document);
d->documentStatusChanged();
}
@@ -329,6 +357,69 @@ QPdfDocument *QPdfView::document() const
}
/*!
+ \since 6.6
+ \property QPdfView::searchModel
+
+ If this property is set, QPdfView draws highlight rectangles over the
+ search results provided by \l QPdfSearchModel::resultsOnPage(). By default
+ it is \c nullptr.
+*/
+void QPdfView::setSearchModel(QPdfSearchModel *searchModel)
+{
+ Q_D(QPdfView);
+ if (d->m_searchModel == searchModel)
+ return;
+
+ if (d->m_searchModel)
+ d->m_searchModel->disconnect(this);
+
+ d->m_searchModel = searchModel;
+ emit searchModelChanged(searchModel);
+
+ if (searchModel) {
+ connect(searchModel, &QPdfSearchModel::dataChanged, this,
+ [this](const QModelIndex &, const QModelIndex &, const QList<int> &) { update(); });
+ }
+ setCurrentSearchResultIndex(-1);
+}
+
+QPdfSearchModel *QPdfView::searchModel() const
+{
+ Q_D(const QPdfView);
+ return d->m_searchModel;
+}
+
+/*!
+ \since 6.6
+ \property QPdfView::currentSearchResultIndex
+
+ If this property is set to a positive number, and \l searchModel is set,
+ QPdfView draws a frame around the search result provided by
+ \l QPdfSearchModel at the given index. For example, if QPdfSearchModel is
+ used as the model for a QListView, you can keep this property updated by
+ connecting QItemSelectionModel::currentChanged() from
+ QListView::selectionModel() to a function that will in turn call this function.
+
+ By default it is \c -1, so that no search results are framed.
+*/
+void QPdfView::setCurrentSearchResultIndex(int currentResult)
+{
+ Q_D(QPdfView);
+ if (d->m_currentSearchResultIndex == currentResult)
+ return;
+
+ d->m_currentSearchResultIndex = currentResult;
+ emit currentSearchResultIndexChanged(currentResult);
+ viewport()->update(); //update();
+}
+
+int QPdfView::currentSearchResultIndex() const
+{
+ Q_D(const QPdfView);
+ return d->m_currentSearchResultIndex;
+}
+
+/*!
This accessor returns the navigation stack that will handle back/forward navigation.
*/
QPdfPageNavigator *QPdfView::pageNavigator() const
@@ -496,9 +587,9 @@ void QPdfView::paintEvent(QPaintEvent *event)
painter.fillRect(event->rect(), palette().brush(QPalette::Dark));
painter.translate(-d->m_viewport.x(), -d->m_viewport.y());
- for (auto it = d->m_documentLayout.pageGeometries.cbegin();
- it != d->m_documentLayout.pageGeometries.cend(); ++it) {
- const QRect pageGeometry = it.value();
+ for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin();
+ it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) {
+ const QRect pageGeometry = it.value().first;
if (pageGeometry.intersects(d->m_viewport)) { // page needs to be painted
painter.fillRect(pageGeometry, Qt::white);
@@ -510,6 +601,44 @@ void QPdfView::paintEvent(QPaintEvent *event)
} else {
d->m_pageRenderer->requestPage(page, pageGeometry.size() * devicePixelRatioF());
}
+
+ const QTransform scaleTransform = d->screenScaleTransform(page);
+#ifdef DEBUG_LINKS
+ const QString fmt = u"page %1 @ %2, %3"_s;
+ d->m_linkModel.setPage(page);
+ const int linkCount = d->m_linkModel.rowCount({});
+ for (int i = 0; i < linkCount; ++i) {
+ const QRectF linkBounds = scaleTransform.mapRect(
+ d->m_linkModel.data(d->m_linkModel.index(i),
+ int(QPdfLinkModel::Role::Rect)).toRectF())
+ .translated(pageGeometry.topLeft());
+ painter.setPen(Qt::blue);
+ painter.drawRect(linkBounds);
+ painter.setPen(Qt::red);
+ const QPoint loc = d->m_linkModel.data(d->m_linkModel.index(i),
+ int(QPdfLinkModel::Role::Location)).toPoint();
+ // TODO maybe draw destination URL if that's what it is
+ painter.drawText(linkBounds.bottomLeft() + QPoint(2, -2),
+ fmt.arg(d->m_linkModel.data(d->m_linkModel.index(i),
+ int(QPdfLinkModel::Role::Page)).toInt())
+ .arg(loc.x()).arg(loc.y()));
+ }
+#endif
+ if (d->m_searchModel) {
+ for (const QPdfLink &result : d->m_searchModel->resultsOnPage(page)) {
+ for (const QRectF &rect : result.rectangles())
+ painter.fillRect(scaleTransform.mapRect(rect).translated(pageGeometry.topLeft()), SearchResultHighlight);
+ }
+
+ if (d->m_currentSearchResultIndex >= 0 && d->m_currentSearchResultIndex < d->m_searchModel->rowCount({})) {
+ const QPdfLink &cur = d->m_searchModel->resultAtIndex(d->m_currentSearchResultIndex);
+ if (cur.page() == page) {
+ painter.setPen({CurrentSearchResultHighlight, CurrentSearchResultWidth});
+ for (const auto &rect : cur.rectangles())
+ painter.drawRect(scaleTransform.mapRect(rect).translated(pageGeometry.topLeft()));
+ }
+ }
+ }
}
}
}
@@ -533,6 +662,52 @@ void QPdfView::scrollContentsBy(int dx, int dy)
d->calculateViewport();
}
+void QPdfView::mousePressEvent(QMouseEvent *event)
+{
+ Q_ASSERT(event->isAccepted());
+}
+
+void QPdfView::mouseMoveEvent(QMouseEvent *event)
+{
+ Q_D(QPdfView);
+ for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin();
+ it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) {
+ const int page = it.key();
+ const QTransform screenInvTransform = d->screenScaleTransform(page).inverted();
+ const QRect pageGeometry = it.value().first;
+ if (pageGeometry.contains(event->position().toPoint())) {
+ const QPointF posInPoints = screenInvTransform.map(event->position() - pageGeometry.topLeft());
+ d->m_linkModel.setPage(page);
+ auto dest = d->m_linkModel.linkAt(posInPoints);
+ setCursor(dest.isValid() ? Qt::PointingHandCursor : Qt::ArrowCursor);
+ if (dest.isValid())
+ qCDebug(qLcLink) << event->position() << ":" << posInPoints << "pt ->" << dest;
+ }
+ }
+}
+
+void QPdfView::mouseReleaseEvent(QMouseEvent *event)
+{
+ Q_D(QPdfView);
+ for (auto it = d->m_documentLayout.pageGeometryAndScale.cbegin();
+ it != d->m_documentLayout.pageGeometryAndScale.cend(); ++it) {
+ const int page = it.key();
+ const QTransform screenInvTransform = d->screenScaleTransform(page).inverted();
+ const QRect pageGeometry = it.value().first;
+ if (pageGeometry.contains(event->position().toPoint())) {
+ const QPointF posInPoints = screenInvTransform.map(event->position() - pageGeometry.topLeft());
+ d->m_linkModel.setPage(page);
+ auto dest = d->m_linkModel.linkAt(posInPoints);
+ if (dest.isValid()) {
+ qCDebug(qLcLink) << event << ": jumping to" << dest;
+ d->m_pageNavigator->jump(dest.page(), dest.location(), dest.zoom());
+ // TODO scroll and zoom to where the link tells us to
+ }
+ return;
+ }
+ }
+}
+
QT_END_NAMESPACE
#include "moc_qpdfview.cpp"
diff --git a/src/pdfwidgets/qpdfview.h b/src/pdfwidgets/qpdfview.h
index 5a4d7ed38..7f1d014de 100644
--- a/src/pdfwidgets/qpdfview.h
+++ b/src/pdfwidgets/qpdfview.h
@@ -1,4 +1,5 @@
// Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QPDFVIEW_H
@@ -11,6 +12,7 @@ QT_BEGIN_NAMESPACE
class QPdfDocument;
class QPdfPageNavigator;
+class QPdfSearchModel;
class QPdfViewPrivate;
class Q_PDF_WIDGETS_EXPORT QPdfView : public QAbstractScrollArea
@@ -26,6 +28,9 @@ class Q_PDF_WIDGETS_EXPORT QPdfView : public QAbstractScrollArea
Q_PROPERTY(int pageSpacing READ pageSpacing WRITE setPageSpacing NOTIFY pageSpacingChanged)
Q_PROPERTY(QMargins documentMargins READ documentMargins WRITE setDocumentMargins NOTIFY documentMarginsChanged)
+ Q_PROPERTY(QPdfSearchModel* searchModel READ searchModel WRITE setSearchModel NOTIFY searchModelChanged)
+ Q_PROPERTY(int currentSearchResultIndex READ currentSearchResultIndex WRITE setCurrentSearchResultIndex NOTIFY currentSearchResultIndexChanged)
+
public:
enum class PageMode
{
@@ -49,6 +54,11 @@ public:
void setDocument(QPdfDocument *document);
QPdfDocument *document() const;
+ QPdfSearchModel *searchModel() const;
+ void setSearchModel(QPdfSearchModel *searchModel);
+
+ int currentSearchResultIndex() const;
+
QPdfPageNavigator *pageNavigator() const;
PageMode pageMode() const;
@@ -65,6 +75,7 @@ public Q_SLOTS:
void setPageMode(QPdfView::PageMode mode);
void setZoomMode(QPdfView::ZoomMode mode);
void setZoomFactor(qreal factor);
+ void setCurrentSearchResultIndex(int currentResult);
Q_SIGNALS:
void documentChanged(QPdfDocument *document);
@@ -73,11 +84,16 @@ Q_SIGNALS:
void zoomFactorChanged(qreal zoomFactor);
void pageSpacingChanged(int pageSpacing);
void documentMarginsChanged(QMargins documentMargins);
+ void searchModelChanged(QPdfSearchModel *searchModel);
+ void currentSearchResultIndexChanged(int currentResult);
protected:
void paintEvent(QPaintEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void scrollContentsBy(int dx, int dy) override;
+ void mousePressEvent(QMouseEvent *event) override;
+ void mouseMoveEvent(QMouseEvent *event) override;
+ void mouseReleaseEvent(QMouseEvent *event) override;
private:
Q_DECLARE_PRIVATE(QPdfView)
diff --git a/src/pdfwidgets/qpdfview_p.h b/src/pdfwidgets/qpdfview_p.h
index 23e83e8eb..d349cc2ee 100644
--- a/src/pdfwidgets/qpdfview_p.h
+++ b/src/pdfwidgets/qpdfview_p.h
@@ -16,6 +16,8 @@
//
#include "qpdfview.h"
+#include "qpdfdocument.h"
+#include "qpdflinkmodel.h"
#include <QHash>
#include <QPointer>
@@ -44,10 +46,12 @@ public:
qreal yPositionForPage(int page) const;
+ QTransform screenScaleTransform(int page) const; // points to pixels
+
struct DocumentLayout
{
QSize documentSize;
- QHash<int, QRect> pageGeometries;
+ QHash<int, QPair<QRect, qreal>> pageGeometryAndScale;
};
DocumentLayout calculateDocumentLayout() const;
@@ -55,13 +59,17 @@ public:
QPdfView *q_ptr;
QPointer<QPdfDocument> m_document;
+ QPointer<QPdfSearchModel> m_searchModel;
QPdfPageNavigator* m_pageNavigator;
QPdfPageRenderer *m_pageRenderer;
+ QPdfLinkModel m_linkModel;
QPdfView::PageMode m_pageMode;
QPdfView::ZoomMode m_zoomMode;
qreal m_zoomFactor;
+ int m_currentSearchResultIndex = -1;
+
int m_pageSpacing;
QMargins m_documentMargins;
diff --git a/src/process/CMakeLists.txt b/src/process/CMakeLists.txt
index 4c283da11..630ba42a8 100644
--- a/src/process/CMakeLists.txt
+++ b/src/process/CMakeLists.txt
@@ -2,7 +2,9 @@
# SPDX-License-Identifier: BSD-3-Clause
if(NOT DEFINED WEBENGINE_ROOT_SOURCE_DIR)
- get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." REALPATH)
+ qt_internal_get_filename_path_mode(path_mode)
+
+ get_filename_component(WEBENGINE_ROOT_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../.." ${path_mode})
endif()
include(${WEBENGINE_ROOT_SOURCE_DIR}/cmake/Functions.cmake)
@@ -23,7 +25,7 @@ if(WIN32)
set_property(TARGET ${qtWebEngineProcessName} PROPERTY WIN32_EXECUTABLE TRUE)
# get libs rsp file, since cmake is not aware of PUBLIC libs for WebEngineCore
get_target_property(libs_rsp WebEngineCore LIBS_RSP)
- target_link_options(${qtWebEngineProcessName} PRIVATE "@${libs_rsp}")
+ target_link_options(${qtWebEngineProcessName} PRIVATE "@${libs_rsp}" "/STACK:0x800000")
endif()
if(MACOS)
@@ -57,18 +59,19 @@ foreach(config ${configs})
set_target_properties(${qtWebEngineProcessName} PROPERTIES
RUNTIME_OUTPUT_DIRECTORY_${config_upper} "${outputPath}"
)
-endforeach()
-if(QT_FEATURE_debug_and_release)
- set_target_properties(${qtWebEngineProcessName} PROPERTIES
- OUTPUT_NAME_DEBUG ${qtWebEngineProcessName}${CMAKE_DEBUG_POSTFIX}
- )
-endif()
+ if("${config}" STREQUAL "Debug")
+ set_target_properties(${qtWebEngineProcessName} PROPERTIES
+ OUTPUT_NAME_DEBUG ${qtWebEngineProcessName}${CMAKE_DEBUG_POSTFIX}
+ )
+ endif()
+endforeach()
if(isFramework)
set_target_properties(${qtWebEngineProcessName} PROPERTIES
MACOSX_BUNDLE TRUE
INSTALL_RPATH "@loader_path/../../../../../../../"
+ MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info_mac.plist.in"
)
target_sources(${qtWebEngineProcessName} PRIVATE QtWebEngineProcess.entitlements)
@@ -87,7 +90,8 @@ if(isFramework)
COMPONENT Runtime
)
qt_enable_separate_debug_info(${qtWebEngineProcessName}
- "${INSTALL_LIBDIR}/QtWebEngineCore.framework/Versions/A/Helpers" QT_EXECUTABLE
+ "${INSTALL_LIBDIR}" QT_EXECUTABLE
+ DSYM_OUTPUT_DIR "${CMAKE_BINARY_DIR}/${INSTALL_LIBDIR}"
)
else()
qt_apply_rpaths(TARGET ${qtWebEngineProcessName} INSTALL_PATH "${INSTALL_LIBEXECDIR}" RELATIVE_RPATH)
diff --git a/src/process/Info_mac.plist.in b/src/process/Info_mac.plist.in
new file mode 100644
index 000000000..22c8c026d
--- /dev/null
+++ b/src/process/Info_mac.plist.in
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+
+ <key>CFBundleName</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>${MACOSX_BUNDLE_GUI_IDENTIFIER}</string>
+ <key>CFBundleExecutable</key>
+ <string>${MACOSX_BUNDLE_EXECUTABLE_NAME}</string>
+
+ <key>CFBundleVersion</key>
+ <string>${MACOSX_BUNDLE_BUNDLE_VERSION}</string>
+ <key>CFBundleShortVersionString</key>
+ <string>${MACOSX_BUNDLE_SHORT_VERSION_STRING}</string>
+
+ <key>LSMinimumSystemVersion</key>
+ <string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
+
+ <key>NSHumanReadableCopyright</key>
+ <string>${MACOSX_BUNDLE_COPYRIGHT}</string>
+
+ <key>CFBundleIconFile</key>
+ <string>${MACOSX_BUNDLE_ICON_FILE}</string>
+
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleAllowMixedLocalizations</key>
+ <true/>
+
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+
+ <key>NSSupportsAutomaticGraphicsSwitching</key>
+ <true/>
+ <key>LSUIElement</key>
+ <true/>
+</dict>
+</plist>
diff --git a/src/process/QtWebEngineProcess.entitlements b/src/process/QtWebEngineProcess.entitlements
index f2fbabddb..59a4b6c15 100644
--- a/src/process/QtWebEngineProcess.entitlements
+++ b/src/process/QtWebEngineProcess.entitlements
@@ -8,5 +8,7 @@
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
+ <key>com.apple.security.cs.disable-executable-page-protection</key>
+ <true/>
</dict>
</plist>
diff --git a/src/webenginequick/CMakeLists.txt b/src/webenginequick/CMakeLists.txt
index 0081edb7f..b7de1c2af 100644
--- a/src/webenginequick/CMakeLists.txt
+++ b/src/webenginequick/CMakeLists.txt
@@ -37,8 +37,8 @@ qt_internal_add_qml_module(WebEngineQuick
api/qquickwebengineforeigntypes_p.h
api/qtwebenginequickglobal.cpp api/qtwebenginequickglobal.h
api/qtwebenginequickglobal_p.h
- render_widget_host_view_qt_delegate_quickwindow.cpp render_widget_host_view_qt_delegate_quickwindow.h
- ui_delegates_manager.cpp ui_delegates_manager.h
+ render_widget_host_view_qt_delegate_quickwindow.cpp render_widget_host_view_qt_delegate_quickwindow_p.h
+ ui_delegates_manager.cpp ui_delegates_manager_p.h
DEFINES
QT_BUILD_WEBENGINE_LIB
INCLUDE_DIRECTORIES
@@ -55,11 +55,17 @@ qt_internal_add_qml_module(WebEngineQuick
Qt::Qml
Qt::Quick
Qt::WebEngineCore
+ NO_GENERATE_CPP_EXPORTS
+)
+
+qt_internal_extend_target(WebEngineQuick CONDITION QT_FEATURE_webengine_webchannel
+ PUBLIC_LIBRARIES
+ Qt::WebChannelQuick
)
qt_internal_extend_target(WebEngineQuick CONDITION QT_FEATURE_accessibility
SOURCES
- qquickwebengine_accessible.cpp qquickwebengine_accessible.h
+ qquickwebengine_accessible.cpp qquickwebengine_accessible_p.h
)
qt_internal_extend_target(qtwebenginequickplugin
diff --git a/src/webenginequick/api/qquickwebengineaction.cpp b/src/webenginequick/api/qquickwebengineaction.cpp
index 70205f883..006715c70 100644
--- a/src/webenginequick/api/qquickwebengineaction.cpp
+++ b/src/webenginequick/api/qquickwebengineaction.cpp
@@ -20,7 +20,7 @@ QT_BEGIN_NAMESPACE
method. It provides information about the action, such as
whether it is \l enabled.
- The following code uses the \l WebEngineView::action() method to check if the
+ The following code uses the \l WebEngineView::action() method to check if
the copy action is enabled:
\code
@@ -30,6 +30,14 @@ QT_BEGIN_NAMESPACE
else
console.log("Copy is disabled.");
\endcode
+
+ A \l ToolButton can be connected to a WebEngineAction as follows:
+
+ \snippet qtwebengine_webengineaction.qml 0
+
+ A context menu could be implemented like this:
+
+ \snippet qtwebengine_webengineaction.qml 1
*/
QQuickWebEngineActionPrivate::QQuickWebEngineActionPrivate(const QVariant &data, const QString &text, const QString &iconName, bool enabled)
diff --git a/src/webenginequick/api/qquickwebengineaction_p.h b/src/webenginequick/api/qquickwebengineaction_p.h
index 51267c166..fcada7773 100644
--- a/src/webenginequick/api/qquickwebengineaction_p.h
+++ b/src/webenginequick/api/qquickwebengineaction_p.h
@@ -29,7 +29,7 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineActionPrivate;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineAction : public QObject
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineAction : public QObject
{
Q_OBJECT
Q_PROPERTY(QString text READ text CONSTANT FINAL)
diff --git a/src/webenginequick/api/qquickwebengineclientcertificateselection_p.h b/src/webenginequick/api/qquickwebengineclientcertificateselection_p.h
index 1c4c214cf..2e0450f8e 100644
--- a/src/webenginequick/api/qquickwebengineclientcertificateselection_p.h
+++ b/src/webenginequick/api/qquickwebengineclientcertificateselection_p.h
@@ -33,7 +33,7 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineClientCertificateSelection;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineClientCertificateOption : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineClientCertificateOption : public QObject {
Q_OBJECT
Q_PROPERTY(QString issuer READ issuer CONSTANT FINAL)
Q_PROPERTY(QString subject READ subject CONSTANT FINAL)
@@ -62,7 +62,7 @@ private:
int m_index;
};
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineClientCertificateSelection : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineClientCertificateSelection : public QObject {
Q_OBJECT
Q_PROPERTY(QUrl host READ host CONSTANT FINAL)
Q_PROPERTY(QQmlListProperty<QQuickWebEngineClientCertificateOption> certificates READ certificates CONSTANT FINAL)
diff --git a/src/webenginequick/api/qquickwebenginedialogrequests.cpp b/src/webenginequick/api/qquickwebenginedialogrequests.cpp
index 3c9f8a9a7..d49f17397 100644
--- a/src/webenginequick/api/qquickwebenginedialogrequests.cpp
+++ b/src/webenginequick/api/qquickwebenginedialogrequests.cpp
@@ -685,6 +685,35 @@ void QQuickWebEngineFileDialogRequest::dialogReject()
\since QtWebEngine 1.10
\brief A request for showing a tooltip to the user.
+
+ A TooltipRequest is a request object that is passed as a
+ parameter of the WebEngineView::tooltipRequested signal. Use the
+ \c onTooltipRequested signal handler to handle requests for
+ custom tooltip menus at specific positions.
+
+ The \l accepted property of the request indicates whether the request
+ is handled by the user code or the default tooltip should
+ be displayed.
+
+ The following code uses a custom tooltip to handle the request:
+
+ \code
+ WebEngineView {
+ // ...
+ onTooltipRequested: function(request) {
+ if (request.type == TooltipRequest.Show) {
+ tooltip.visible = true;
+ tooltip.x = request.x;
+ tooltip.y = request.y;
+ tooltip.text = request.text;
+ } else {
+ tooltip.visible = false;
+ }
+ request.accepted = true;
+ }
+ // ...
+ }
+ \endcode
*/
QQuickWebEngineTooltipRequest::QQuickWebEngineTooltipRequest(
diff --git a/src/webenginequick/api/qquickwebenginedialogrequests_p.h b/src/webenginequick/api/qquickwebenginedialogrequests_p.h
index e83481400..d33a14df4 100644
--- a/src/webenginequick/api/qquickwebenginedialogrequests_p.h
+++ b/src/webenginequick/api/qquickwebenginedialogrequests_p.h
@@ -32,7 +32,7 @@ namespace QtWebEngineCore {
QT_BEGIN_NAMESPACE
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineAuthenticationDialogRequest : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineAuthenticationDialogRequest : public QObject {
Q_OBJECT
public:
@@ -79,7 +79,7 @@ private:
Q_DISABLE_COPY(QQuickWebEngineAuthenticationDialogRequest)
};
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineJavaScriptDialogRequest : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineJavaScriptDialogRequest : public QObject {
Q_OBJECT
public:
@@ -130,7 +130,7 @@ private:
Q_DISABLE_COPY(QQuickWebEngineJavaScriptDialogRequest)
};
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineColorDialogRequest : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineColorDialogRequest : public QObject {
Q_OBJECT
public:
@@ -161,7 +161,7 @@ private:
Q_DISABLE_COPY(QQuickWebEngineColorDialogRequest)
};
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineFileDialogRequest : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineFileDialogRequest : public QObject {
Q_OBJECT
public:
@@ -206,7 +206,7 @@ private:
Q_DISABLE_COPY(QQuickWebEngineFileDialogRequest)
};
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineTooltipRequest : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineTooltipRequest : public QObject {
Q_OBJECT
public:
enum RequestType {
diff --git a/src/webenginequick/api/qquickwebenginedownloadrequest_p.h b/src/webenginequick/api/qquickwebenginedownloadrequest_p.h
index 2d4ac0773..42a0d88ba 100644
--- a/src/webenginequick/api/qquickwebenginedownloadrequest_p.h
+++ b/src/webenginequick/api/qquickwebenginedownloadrequest_p.h
@@ -24,7 +24,7 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineProfilePrivate;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineDownloadRequest : public QWebEngineDownloadRequest
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineDownloadRequest : public QWebEngineDownloadRequest
{
Q_OBJECT
public:
diff --git a/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h b/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h
index b83db2cb4..89bfb6e73 100644
--- a/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h
+++ b/src/webenginequick/api/qquickwebenginefaviconprovider_p_p.h
@@ -67,7 +67,7 @@ private:
QImage m_image;
};
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineFaviconProvider : public QQuickAsyncImageProvider
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineFaviconProvider : public QQuickAsyncImageProvider
{
public:
static QString identifier();
diff --git a/src/webenginequick/api/qquickwebengineforeigntypes_p.h b/src/webenginequick/api/qquickwebengineforeigntypes_p.h
index d8351c855..2d205254e 100644
--- a/src/webenginequick/api/qquickwebengineforeigntypes_p.h
+++ b/src/webenginequick/api/qquickwebengineforeigntypes_p.h
@@ -30,13 +30,22 @@
#include <QtWebEngineCore/qwebenginefullscreenrequest.h>
#include <QtWebEngineCore/qwebenginecontextmenurequest.h>
#include <QtWebEngineCore/qwebengineregisterprotocolhandlerrequest.h>
+#include <QtWebEngineCore/qwebenginefilesystemaccessrequest.h>
+#include <QtWebEngineCore/qwebenginewebauthuxrequest.h>
QT_BEGIN_NAMESPACE
+// To prevent the same type from being exported twice into qmltypes
+// (for value type and for the enums)
+struct QWebEngineLoadingInfoDerived : public QWebEngineLoadingInfo
+{
+ Q_GADGET
+};
+
namespace ForeignWebEngineLoadingInfoNamespace
{
Q_NAMESPACE
- QML_FOREIGN_NAMESPACE(QWebEngineLoadingInfo)
+ QML_FOREIGN_NAMESPACE(QWebEngineLoadingInfoDerived)
QML_NAMED_ELEMENT(WebEngineLoadingInfo)
QML_ADDED_IN_VERSION(1, 1)
QML_EXTRA_VERSION(2, 0)
@@ -52,10 +61,17 @@ struct ForeignWebEngineLoadingInfo
QML_UNCREATABLE("")
};
+// To prevent the same type from being exported twice into qmltypes
+// (for value type and for the enums)
+struct QWebEngineCertificateErrorDerived : public QWebEngineCertificateError
+{
+ Q_GADGET
+};
+
namespace ForeignWebEngineCertificateErrorNamespace
{
Q_NAMESPACE
- QML_FOREIGN_NAMESPACE(QWebEngineCertificateError)
+ QML_FOREIGN_NAMESPACE(QWebEngineCertificateErrorDerived)
QML_NAMED_ELEMENT(WebEngineCertificateError)
QML_ADDED_IN_VERSION(1, 1)
QML_EXTRA_VERSION(2, 0)
@@ -140,6 +156,7 @@ struct ForeignWebEngineContextMenuRequest
QML_UNCREATABLE("")
};
+#if QT_DEPRECATED_SINCE(6, 5)
struct ForeignWebEngineQuotaRequest
{
Q_GADGET
@@ -149,6 +166,7 @@ struct ForeignWebEngineQuotaRequest
QML_EXTRA_VERSION(2, 0)
QML_UNCREATABLE("")
};
+#endif
struct ForeignWebEngineRegisterProtocolHandlerRequest
{
@@ -180,6 +198,39 @@ struct ForeignWebEngineFindTextResult
QML_UNCREATABLE("")
};
+struct ForeginWebEngineFileSystemAccessRequest
+{
+ Q_GADGET
+ QML_FOREIGN(QWebEngineFileSystemAccessRequest)
+ QML_NAMED_ELEMENT(webEngineFileSystemAccessRequest)
+ QML_ADDED_IN_VERSION(6, 4)
+ QML_UNCREATABLE("")
+};
+
+// To prevent the same type from being exported twice into qmltypes
+// (for value type and for the enums)
+struct QWebEngineFileSystemAccessRequestDerived : public QWebEngineFileSystemAccessRequest
+{
+ Q_GADGET
+};
+
+namespace ForeginWebEngineFileSystemAccessRequestNamespace
+{
+ Q_NAMESPACE
+ QML_FOREIGN_NAMESPACE(QWebEngineFileSystemAccessRequestDerived)
+ QML_NAMED_ELEMENT(WebEngineFileSystemAccessRequest)
+ QML_ADDED_IN_VERSION(6, 4)
+};
+
+struct ForeignWebEngineWebAuthUxRequest
+{
+ Q_GADGET
+ QML_FOREIGN(QWebEngineWebAuthUxRequest)
+ QML_NAMED_ELEMENT(WebEngineWebAuthUxRequest)
+ QML_ADDED_IN_VERSION(6, 7)
+ QML_UNCREATABLE("")
+};
+
QT_END_NAMESPACE
#endif // QQUICKWEBENGINEFOREIGNTYPES_H
diff --git a/src/webenginequick/api/qquickwebenginenewwindowrequest_p.h b/src/webenginequick/api/qquickwebenginenewwindowrequest_p.h
index 39655696e..f170fa0c6 100644
--- a/src/webenginequick/api/qquickwebenginenewwindowrequest_p.h
+++ b/src/webenginequick/api/qquickwebenginenewwindowrequest_p.h
@@ -23,7 +23,7 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineView;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineNewWindowRequest : public QWebEngineNewWindowRequest
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineNewWindowRequest : public QWebEngineNewWindowRequest
{
Q_OBJECT
public:
diff --git a/src/webenginequick/api/qquickwebengineprofile.cpp b/src/webenginequick/api/qquickwebengineprofile.cpp
index 1badd25be..7c3d11fcf 100644
--- a/src/webenginequick/api/qquickwebengineprofile.cpp
+++ b/src/webenginequick/api/qquickwebengineprofile.cpp
@@ -14,6 +14,7 @@
#include <QtWebEngineCore/qwebenginescriptcollection.h>
#include <QtWebEngineCore/private/qwebenginescriptcollection_p.h>
+#include <QtWebEngineCore/qwebengineclienthints.h>
#include <QtWebEngineCore/qwebenginecookiestore.h>
#include <QtWebEngineCore/qwebenginenotification.h>
#include <QtWebEngineCore/private/qwebenginedownloadrequest_p.h>
@@ -124,8 +125,18 @@ QT_BEGIN_NAMESPACE
\sa WebEngineProfile::presentNotification
*/
+/*!
+ \fn QQuickWebEngineProfile::clearHttpCacheCompleted()
+ \since 6.7
+
+ This signal is emitted when the clearHttpCache() operation is completed.
+
+ \sa clearHttpCache()
+*/
+
QQuickWebEngineProfilePrivate::QQuickWebEngineProfilePrivate(ProfileAdapter *profileAdapter)
: m_settings(new QQuickWebEngineSettings())
+ , m_clientHints(new QWebEngineClientHints(profileAdapter))
, m_profileAdapter(profileAdapter)
{
profileAdapter->addClient(this);
@@ -209,10 +220,13 @@ void QQuickWebEngineProfilePrivate::downloadRequested(DownloadItemInfo &info)
Q_Q(QQuickWebEngineProfile);
Q_ASSERT(!m_ongoingDownloads.contains(info.id));
- QWebEngineDownloadRequestPrivate *itemPrivate = new QWebEngineDownloadRequestPrivate(m_profileAdapter, info.url);
+ QWebEngineDownloadRequestPrivate *itemPrivate =
+ new QWebEngineDownloadRequestPrivate(m_profileAdapter);
itemPrivate->downloadId = info.id;
- itemPrivate->downloadState = QWebEngineDownloadRequest::DownloadRequested;
+ itemPrivate->downloadState = info.accepted ? QWebEngineDownloadRequest::DownloadInProgress
+ : QWebEngineDownloadRequest::DownloadRequested;
itemPrivate->startTime = info.startTime;
+ itemPrivate->downloadUrl = info.url;
itemPrivate->totalBytes = info.totalBytes;
itemPrivate->mimeType = info.mimeType;
itemPrivate->downloadDirectory = QFileInfo(info.path).path();
@@ -276,6 +290,12 @@ void QQuickWebEngineProfilePrivate::showNotification(QSharedPointer<QtWebEngineC
Q_EMIT q->presentNotification(notification);
}
+void QQuickWebEngineProfilePrivate::clearHttpCacheCompleted()
+{
+ Q_Q(QQuickWebEngineProfile);
+ Q_EMIT q->clearHttpCacheCompleted();
+}
+
QQuickWebEngineScriptCollection *QQuickWebEngineProfilePrivate::getUserScripts()
{
Q_Q(QQuickWebEngineProfile);
@@ -322,16 +342,16 @@ QQuickWebEngineScriptCollection *QQuickWebEngineProfilePrivate::getUserScripts()
*/
/*!
- \qmlsignal WebEngineProfile::downloadRequested(WebEngineDownloadItem download)
+ \qmlsignal WebEngineProfile::downloadRequested(WebEngineDownloadRequest download)
This signal is emitted whenever a download has been triggered.
The \a download argument holds the state of the download.
- The download has to be explicitly accepted with WebEngineDownloadItem::accept() or the
+ The download has to be explicitly accepted with WebEngineDownloadRequest::accept() or the
download will be cancelled by default.
*/
/*!
- \qmlsignal WebEngineProfile::downloadFinished(WebEngineDownloadItem download)
+ \qmlsignal WebEngineProfile::downloadFinished(WebEngineDownloadRequest download)
This signal is emitted whenever downloading stops, because it finished successfully, was
cancelled, or was interrupted (for example, because connectivity was lost).
@@ -348,6 +368,15 @@ QQuickWebEngineScriptCollection *QQuickWebEngineProfilePrivate::getUserScripts()
*/
/*!
+ \qmlsignal WebEngineProfile::clearHttpCacheCompleted()
+ \since QtWebEngine 6.7
+
+ This signal is emitted when the clearHttpCache() operation is completed.
+
+ \sa clearHttpCache()
+*/
+
+/*!
Constructs a new profile with the parent \a parent.
*/
QQuickWebEngineProfile::QQuickWebEngineProfile(QObject *parent)
@@ -871,7 +900,11 @@ QWebEngineCookieStore *QQuickWebEngineProfile::cookieStore() const
Removes the profile's cache entries.
- \sa WebEngineProfile::cachePath
+ \note Make sure that you do not start new navigation or any operation on the profile while
+ the clear operation is in progress. The clearHttpCacheCompleted() signal notifies about the
+ completion.
+
+ \sa WebEngineProfile::cachePath clearHttpCacheCompleted()
*/
/*!
@@ -879,7 +912,11 @@ QWebEngineCookieStore *QQuickWebEngineProfile::cookieStore() const
Removes the profile's cache entries.
- \sa WebEngineProfile::clearHttpCache
+ \note Make sure that you do not start new navigation or any operation on the profile while
+ the clear operation is in progress. The clearHttpCacheCompleted() signal notifies about the
+ completion.
+
+ \sa WebEngineProfile::clearHttpCache() clearHttpCacheCompleted()
*/
void QQuickWebEngineProfile::clearHttpCache()
{
@@ -987,6 +1024,18 @@ QWebEngineClientCertificateStore *QQuickWebEngineProfile::clientCertificateStore
#endif
}
+/*!
+ Return the Client Hints settings associated with this browsing context.
+
+ \since 6.8
+ \sa QWebEngineClientHints
+*/
+QWebEngineClientHints *QQuickWebEngineProfile::clientHints() const
+{
+ Q_D(const QQuickWebEngineProfile);
+ return d->m_clientHints.data();
+}
+
void QQuickWebEngineProfile::ensureQmlContext(const QObject *object)
{
if (!qmlContext(this)) {
diff --git a/src/webenginequick/api/qquickwebengineprofile.h b/src/webenginequick/api/qquickwebengineprofile.h
index 29d6ee0b2..088a971e0 100644
--- a/src/webenginequick/api/qquickwebengineprofile.h
+++ b/src/webenginequick/api/qquickwebengineprofile.h
@@ -15,6 +15,7 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineDownloadRequest;
class QQuickWebEngineSettings;
class QWebEngineClientCertificateStore;
+class QWebEngineClientHints;
class QWebEngineCookieStore;
class QWebEngineNotification;
class QWebEngineUrlRequestInterceptor;
@@ -113,6 +114,7 @@ public:
void setPushServiceEnabled(bool enable);
QWebEngineClientCertificateStore *clientCertificateStore();
+ QWebEngineClientHints *clientHints() const;
static QQuickWebEngineProfile *defaultProfile();
@@ -130,6 +132,7 @@ Q_SIGNALS:
Q_REVISION(1,3) void spellCheckEnabledChanged();
Q_REVISION(1,5) void downloadPathChanged();
Q_REVISION(6,5) void pushServiceEnabledChanged();
+ Q_REVISION(6,7) void clearHttpCacheCompleted();
void downloadRequested(QQuickWebEngineDownloadRequest *download);
void downloadFinished(QQuickWebEngineDownloadRequest *download);
diff --git a/src/webenginequick/api/qquickwebengineprofile_p.h b/src/webenginequick/api/qquickwebengineprofile_p.h
index e7d72af17..477936f98 100644
--- a/src/webenginequick/api/qquickwebengineprofile_p.h
+++ b/src/webenginequick/api/qquickwebengineprofile_p.h
@@ -28,6 +28,7 @@ class ProfileAdapter;
QT_BEGIN_NAMESPACE
+class QWebEngineClientHints;
class QQuickWebEngineDownloadRequest;
class QQuickWebEngineSettings;
class QQuickWebEngineScriptCollection;
@@ -53,10 +54,12 @@ public:
void downloadUpdated(const DownloadItemInfo &info) override;
void showNotification(QSharedPointer<QtWebEngineCore::UserNotificationController> &controller) override;
+ void clearHttpCacheCompleted() override;
private:
QQuickWebEngineProfile *q_ptr;
QScopedPointer<QQuickWebEngineSettings> m_settings;
+ QScopedPointer<QWebEngineClientHints> m_clientHints;
QPointer<QtWebEngineCore::ProfileAdapter> m_profileAdapter;
QMap<quint32, QPointer<QQuickWebEngineDownloadRequest> > m_ongoingDownloads;
diff --git a/src/webenginequick/api/qquickwebenginescriptcollection_p.h b/src/webenginequick/api/qquickwebenginescriptcollection_p.h
index 657fd5554..fbcc8dde7 100644
--- a/src/webenginequick/api/qquickwebenginescriptcollection_p.h
+++ b/src/webenginequick/api/qquickwebenginescriptcollection_p.h
@@ -26,7 +26,7 @@ QT_BEGIN_NAMESPACE
class QQmlEngine;
class QQuickWebEngineScriptCollectionPrivate;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineScriptCollection : public QObject
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineScriptCollection : public QObject
{
Q_OBJECT
public:
diff --git a/src/webenginequick/api/qquickwebenginesettings.cpp b/src/webenginequick/api/qquickwebenginesettings.cpp
index 6d64c1d3b..31ed7a661 100644
--- a/src/webenginequick/api/qquickwebenginesettings.cpp
+++ b/src/webenginequick/api/qquickwebenginesettings.cpp
@@ -77,6 +77,10 @@ bool QQuickWebEngineSettings::javascriptCanOpenWindows() const
To enable also the pasting of clipboard content from JavaScript,
use javascriptCanPaste.
+ Since unrestricted clipboard access is a potential security concern, it is
+ recommended that applications leave this disabled and instead respond to
+ \l{WebEngineView::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests.
+
Disabled by default.
*/
bool QQuickWebEngineSettings::javascriptCanAccessClipboard() const
@@ -383,6 +387,10 @@ bool QQuickWebEngineSettings::webRTCPublicInterfacesOnly() const
Enables JavaScript \c{execCommand("paste")}.
This also requires enabling javascriptCanAccessClipboard.
+ Since unrestricted clipboard access is a potential security concern, it is
+ recommended that applications leave this disabled and instead respond to
+ \l{WebEngineView::ClipboardReadWrite}{ClipboardReadWrite} feature permission requests.
+
Disabled by default.
*/
bool QQuickWebEngineSettings::javascriptCanPaste() const
@@ -433,6 +441,48 @@ bool QQuickWebEngineSettings::navigateOnDropEnabled() const
}
/*!
+ \qmlproperty bool WebEngineSettings::readingFromCanvasEnabled
+ \since QtWebEngine 6.6
+
+ Specifies that reading from all canvas elements is enabled.
+
+ This setting will have impact on all HTML5 canvas elements irrespective of origin, and can be disabled
+ to prevent canvas fingerprinting.
+
+ Enabled by default.
+ */
+bool QQuickWebEngineSettings::readingFromCanvasEnabled() const
+{
+ return d_ptr->testAttribute(QWebEngineSettings::ReadingFromCanvasEnabled);
+}
+
+/*!
+ \qmlproperty bool WebEngineSettings::forceDarkMode
+ \since QtWebEngine 6.7
+
+ Automatically render all web contents using a dark theme.
+
+ Disabled by default.
+ */
+bool QQuickWebEngineSettings::forceDarkMode() const
+{
+ return d_ptr->testAttribute(QWebEngineSettings::ForceDarkMode);
+}
+
+/*!
+ \qmlproperty bool WebEngineSettings::scrollAnimatorEnabled
+ \since QtWebEngine 6.8
+
+ Enables animated scrolling.
+
+ Disabled by default.
+ */
+bool QQuickWebEngineSettings::scrollAnimatorEnabled() const
+{
+ return d_ptr->testAttribute(QWebEngineSettings::ScrollAnimatorEnabled);
+}
+
+/*!
\qmlproperty string WebEngineSettings::defaultTextEncoding
\since QtWebEngine 1.2
@@ -446,6 +496,33 @@ QString QQuickWebEngineSettings::defaultTextEncoding() const
return d_ptr->defaultTextEncoding();
}
+ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::AllowImageAnimation,
+ QWebEngineSettings::AllowImageAnimation)
+ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::AnimateImageOnce, QWebEngineSettings::AnimateImageOnce)
+ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::DisallowImageAnimation,
+ QWebEngineSettings::DisallowImageAnimation)
+/*!
+ \qmlproperty enumeration WebEngineSettings::imageAnimationPolicy
+ \since QtWebEngine 6.8
+
+ Specifies how an image animation should be handled when the image frames
+ are rendered for animation.
+
+ \value WebEngineSettings.AllowImageAnimation
+ Allows all image animations when the image frames are rendered.
+ \value WebEngineSettings.AnimateImageOnce
+ Animate the image once when the image frames are rendered.
+ \value WebEngineSettings.DisallowImageAnimation
+ Disallows all image animations when the image frames are rendered.
+
+ Default value is \c {WebEngineSettings.AllowImageAnimation}.
+*/
+QQuickWebEngineSettings::ImageAnimationPolicy QQuickWebEngineSettings::imageAnimationPolicy() const
+{
+ return static_cast<QQuickWebEngineSettings::ImageAnimationPolicy>(
+ d_ptr->imageAnimationPolicy());
+}
+
ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::DisallowUnknownUrlSchemes, QWebEngineSettings::DisallowUnknownUrlSchemes)
ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction, QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction)
ASSERT_ENUMS_MATCH(QQuickWebEngineSettings::AllowAllUnknownUrlSchemes, QWebEngineSettings::AllowAllUnknownUrlSchemes)
@@ -715,6 +792,30 @@ void QQuickWebEngineSettings::setNavigateOnDropEnabled(bool on)
Q_EMIT navigateOnDropEnabledChanged();
}
+void QQuickWebEngineSettings::setReadingFromCanvasEnabled(bool on)
+{
+ bool wasOn = d_ptr->testAttribute(QWebEngineSettings::ReadingFromCanvasEnabled);
+ d_ptr->setAttribute(QWebEngineSettings::ReadingFromCanvasEnabled, on);
+ if (wasOn != on)
+ Q_EMIT readingFromCanvasEnabledChanged();
+}
+
+void QQuickWebEngineSettings::setForceDarkMode(bool on)
+{
+ bool wasOn = d_ptr->testAttribute(QWebEngineSettings::ForceDarkMode);
+ d_ptr->setAttribute(QWebEngineSettings::ForceDarkMode, on);
+ if (wasOn != on)
+ Q_EMIT forceDarkModeChanged();
+}
+
+void QQuickWebEngineSettings::setScrollAnimatorEnabled(bool on)
+{
+ bool wasOn = d_ptr->testAttribute(QWebEngineSettings::ScrollAnimatorEnabled);
+ d_ptr->setAttribute(QWebEngineSettings::ScrollAnimatorEnabled, on);
+ if (wasOn != on)
+ Q_EMIT scrollAnimatorEnabledChanged();
+}
+
void QQuickWebEngineSettings::setUnknownUrlSchemePolicy(QQuickWebEngineSettings::UnknownUrlSchemePolicy policy)
{
QWebEngineSettings::UnknownUrlSchemePolicy oldPolicy = d_ptr->unknownUrlSchemePolicy();
@@ -737,6 +838,17 @@ void QQuickWebEngineSettings::setParentSettings(QQuickWebEngineSettings *parentS
d_ptr->setParentSettings(parentSettings->d_ptr.data());
}
+void QQuickWebEngineSettings::setImageAnimationPolicy(
+ QQuickWebEngineSettings::ImageAnimationPolicy policy)
+{
+ QWebEngineSettings::ImageAnimationPolicy oldPolicy = d_ptr->imageAnimationPolicy();
+ QWebEngineSettings::ImageAnimationPolicy newPolicy =
+ static_cast<QWebEngineSettings::ImageAnimationPolicy>(policy);
+ d_ptr->setImageAnimationPolicy(newPolicy);
+ if (oldPolicy != newPolicy)
+ Q_EMIT imageAnimationPolicyChanged();
+}
+
QT_END_NAMESPACE
#include "moc_qquickwebenginesettings_p.cpp"
diff --git a/src/webenginequick/api/qquickwebenginesettings_p.h b/src/webenginequick/api/qquickwebenginesettings_p.h
index 71081c232..ed3c77884 100644
--- a/src/webenginequick/api/qquickwebenginesettings_p.h
+++ b/src/webenginequick/api/qquickwebenginesettings_p.h
@@ -23,7 +23,7 @@
QT_BEGIN_NAMESPACE
class QWebEngineSettings;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineSettings : public QObject {
Q_OBJECT
Q_PROPERTY(bool autoLoadImages READ autoLoadImages WRITE setAutoLoadImages NOTIFY autoLoadImagesChanged FINAL)
Q_PROPERTY(bool javascriptEnabled READ javascriptEnabled WRITE setJavascriptEnabled NOTIFY javascriptEnabledChanged FINAL)
@@ -57,6 +57,10 @@ class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineSettings : public QObject {
Q_PROPERTY(bool dnsPrefetchEnabled READ dnsPrefetchEnabled WRITE setDnsPrefetchEnabled NOTIFY dnsPrefetchEnabledChanged REVISION(1,7) FINAL)
Q_PROPERTY(bool pdfViewerEnabled READ pdfViewerEnabled WRITE setPdfViewerEnabled NOTIFY pdfViewerEnabledChanged REVISION(1,8) FINAL)
Q_PROPERTY(bool navigateOnDropEnabled READ navigateOnDropEnabled WRITE setNavigateOnDropEnabled NOTIFY navigateOnDropEnabledChanged REVISION(6,4) FINAL)
+ Q_PROPERTY(bool readingFromCanvasEnabled READ readingFromCanvasEnabled WRITE setReadingFromCanvasEnabled NOTIFY readingFromCanvasEnabledChanged REVISION(6,6) FINAL)
+ Q_PROPERTY(bool forceDarkMode READ forceDarkMode WRITE setForceDarkMode NOTIFY forceDarkModeChanged REVISION(6,7) FINAL)
+ Q_PROPERTY(bool scrollAnimatorEnabled READ scrollAnimatorEnabled WRITE setScrollAnimatorEnabled NOTIFY scrollAnimatorEnabledChanged REVISION(6,8) FINAL)
+ Q_PROPERTY(ImageAnimationPolicy imageAnimationPolicy READ imageAnimationPolicy WRITE setImageAnimationPolicy NOTIFY imageAnimationPolicyChanged REVISION(6,8) FINAL)
QML_NAMED_ELEMENT(WebEngineSettings)
QML_ADDED_IN_VERSION(1, 1)
QML_EXTRA_VERSION(2, 0)
@@ -70,6 +74,14 @@ public:
Q_ENUM(UnknownUrlSchemePolicy)
+ enum ImageAnimationPolicy {
+ AllowImageAnimation = 1,
+ AnimateImageOnce,
+ DisallowImageAnimation
+ };
+
+ Q_ENUM(ImageAnimationPolicy)
+
~QQuickWebEngineSettings();
bool autoLoadImages() const;
@@ -104,6 +116,10 @@ public:
bool dnsPrefetchEnabled() const;
bool pdfViewerEnabled() const;
bool navigateOnDropEnabled() const;
+ bool readingFromCanvasEnabled() const;
+ bool forceDarkMode() const;
+ bool scrollAnimatorEnabled() const;
+ ImageAnimationPolicy imageAnimationPolicy() const;
void setAutoLoadImages(bool on);
void setJavascriptEnabled(bool on);
@@ -137,6 +153,10 @@ public:
void setDnsPrefetchEnabled(bool on);
void setPdfViewerEnabled(bool on);
void setNavigateOnDropEnabled(bool on);
+ void setReadingFromCanvasEnabled(bool on);
+ void setForceDarkMode(bool on);
+ void setScrollAnimatorEnabled(bool on);
+ void setImageAnimationPolicy(ImageAnimationPolicy policy);
signals:
void autoLoadImagesChanged();
@@ -171,6 +191,10 @@ signals:
Q_REVISION(1,7) void dnsPrefetchEnabledChanged();
Q_REVISION(1,8) void pdfViewerEnabledChanged();
Q_REVISION(6,4) void navigateOnDropEnabledChanged();
+ Q_REVISION(6,6) void readingFromCanvasEnabledChanged();
+ Q_REVISION(6,7) void forceDarkModeChanged();
+ Q_REVISION(6,8) void scrollAnimatorEnabledChanged();
+ Q_REVISION(6,8) void imageAnimationPolicyChanged();
private:
explicit QQuickWebEngineSettings(QQuickWebEngineSettings *parentSettings = nullptr);
diff --git a/src/webenginequick/api/qquickwebenginesingleton_p.h b/src/webenginequick/api/qquickwebenginesingleton_p.h
index 6ac8aef8c..b05daecd6 100644
--- a/src/webenginequick/api/qquickwebenginesingleton_p.h
+++ b/src/webenginequick/api/qquickwebenginesingleton_p.h
@@ -25,7 +25,7 @@ QT_BEGIN_NAMESPACE
class QQuickWebEngineSettings;
class QQuickWebEngineProfile;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineSingleton : public QObject {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineSingleton : public QObject {
Q_OBJECT
Q_PROPERTY(QQuickWebEngineSettings* settings READ settings CONSTANT FINAL)
Q_PROPERTY(QQuickWebEngineProfile* defaultProfile READ defaultProfile CONSTANT FINAL REVISION(1,1))
diff --git a/src/webenginequick/api/qquickwebenginetouchhandleprovider_p_p.h b/src/webenginequick/api/qquickwebenginetouchhandleprovider_p_p.h
index 762bc6fcf..92a13b08e 100644
--- a/src/webenginequick/api/qquickwebenginetouchhandleprovider_p_p.h
+++ b/src/webenginequick/api/qquickwebenginetouchhandleprovider_p_p.h
@@ -20,7 +20,7 @@
QT_BEGIN_NAMESPACE
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineTouchHandleProvider : public QQuickImageProvider {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineTouchHandleProvider : public QQuickImageProvider {
public:
static QString identifier();
static QUrl url(int orientation);
diff --git a/src/webenginequick/api/qquickwebengineview.cpp b/src/webenginequick/api/qquickwebengineview.cpp
index 9eb8a1e2a..78248346b 100644
--- a/src/webenginequick/api/qquickwebengineview.cpp
+++ b/src/webenginequick/api/qquickwebengineview.cpp
@@ -25,23 +25,28 @@
#include "find_text_helper.h"
#include "javascript_dialog_controller.h"
#include "render_widget_host_view_qt_delegate_item.h"
-#include "render_widget_host_view_qt_delegate_quickwindow.h"
+#include "render_widget_host_view_qt_delegate_quickwindow_p.h"
#include "touch_selection_menu_controller.h"
-#include "ui_delegates_manager.h"
+#include "ui_delegates_manager_p.h"
#include "web_contents_adapter.h"
#include <QtWebEngineCore/qwebenginecertificateerror.h>
+#include <QtWebEngineCore/qwebenginedesktopmediarequest.h>
#include <QtWebEngineCore/qwebenginefilesystemaccessrequest.h>
#include <QtWebEngineCore/qwebenginefindtextresult.h>
#include <QtWebEngineCore/qwebenginefullscreenrequest.h>
#include <QtWebEngineCore/qwebengineloadinginfo.h>
#include <QtWebEngineCore/qwebenginenavigationrequest.h>
+#include <QtWebEngineCore/qwebenginepage.h>
#include <QtWebEngineCore/qwebengineregisterprotocolhandlerrequest.h>
#include <QtWebEngineCore/qwebenginescriptcollection.h>
+#include <QtWebEngineCore/qwebenginewebauthuxrequest.h>
#include <QtWebEngineCore/private/qwebenginecontextmenurequest_p.h>
+#include <QtWebEngineCore/private/qwebenginedesktopmediarequest_p.h>
#include <QtWebEngineCore/private/qwebenginehistory_p.h>
#include <QtWebEngineCore/private/qwebenginenewwindowrequest_p.h>
#include <QtWebEngineCore/private/qwebenginescriptcollection_p.h>
+#include <QtWebEngineCore/private/qwebenginepage_p.h>
#include <QtWebEngineCore/private/qtwebenginecoreglobal_p.h>
#include <QtCore/qloggingcategory.h>
@@ -58,7 +63,7 @@
#include <QtQml/qqmlproperty.h>
#if QT_CONFIG(accessibility)
-#include "qquickwebengine_accessible.h"
+#include "qquickwebengine_accessible_p.h"
#include <QtGui/qaccessible.h>
#endif
@@ -71,12 +76,15 @@
#endif
#if QT_CONFIG(webengine_webchannel)
-#include <QtWebChannel/qqmlwebchannel.h>
+#include <QtWebChannelQuick/qqmlwebchannel.h>
#endif
QT_BEGIN_NAMESPACE
using namespace QtWebEngineCore;
+Q_STATIC_ASSERT(int(QQuickWebEngineView::WebActionCount) == int(QWebEnginePage::WebActionCount));
+using LoadStatus = QWebEngineLoadingInfo::LoadStatus;
+using ErrorDomain = QWebEngineLoadingInfo::ErrorDomain;
#if QT_DEPRECATED_SINCE(6, 2)
QT_WARNING_PUSH QT_WARNING_DISABLE_DEPRECATED
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::AcceptRequest) == static_cast<int>(QWebEngineNavigationRequest::AcceptRequest));
@@ -92,9 +100,6 @@ Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::NewViewInWindow)
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::NewViewInTab) == static_cast<int>(QWebEngineNewWindowRequest::InNewTab));
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::NewViewInDialog) == static_cast<int>(QWebEngineNewWindowRequest::InNewDialog));
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::NewViewInBackgroundTab) == static_cast<int>(QWebEngineNewWindowRequest::InNewBackgroundTab));
-
-using LoadStatus = QWebEngineLoadingInfo::LoadStatus;
-using ErrorDomain = QWebEngineLoadingInfo::ErrorDomain;
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::NoErrorDomain) == static_cast<int>(ErrorDomain::NoErrorDomain));
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::InternalErrorDomain) == static_cast<int>(ErrorDomain::InternalErrorDomain));
Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::ConnectionErrorDomain) == static_cast<int>(ErrorDomain::ConnectionErrorDomain));
@@ -109,6 +114,134 @@ Q_STATIC_ASSERT(static_cast<int>(QQuickWebEngineView::LoadSucceededStatus) == st
QT_WARNING_POP
#endif
+#if QT_CONFIG(webengine_printing_and_pdf)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Letter, QQuickWebEngineView::PrintedPageSizeId::Letter)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Legal, QQuickWebEngineView::PrintedPageSizeId::Legal)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Executive, QQuickWebEngineView::PrintedPageSizeId::Executive)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A0, QQuickWebEngineView::PrintedPageSizeId::A0)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A1, QQuickWebEngineView::PrintedPageSizeId::A1)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A2, QQuickWebEngineView::PrintedPageSizeId::A2)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A3, QQuickWebEngineView::PrintedPageSizeId::A3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A4, QQuickWebEngineView::PrintedPageSizeId::A4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A5, QQuickWebEngineView::PrintedPageSizeId::A5)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A6, QQuickWebEngineView::PrintedPageSizeId::A6)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A7, QQuickWebEngineView::PrintedPageSizeId::A7)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A8, QQuickWebEngineView::PrintedPageSizeId::A8)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A9, QQuickWebEngineView::PrintedPageSizeId::A9)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A10, QQuickWebEngineView::PrintedPageSizeId::A10)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B0, QQuickWebEngineView::PrintedPageSizeId::B0)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B1, QQuickWebEngineView::PrintedPageSizeId::B1)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B2, QQuickWebEngineView::PrintedPageSizeId::B2)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B3, QQuickWebEngineView::PrintedPageSizeId::B3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B4, QQuickWebEngineView::PrintedPageSizeId::B4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B5, QQuickWebEngineView::PrintedPageSizeId::B5)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B6, QQuickWebEngineView::PrintedPageSizeId::B6)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B7, QQuickWebEngineView::PrintedPageSizeId::B7)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B8, QQuickWebEngineView::PrintedPageSizeId::B8)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B9, QQuickWebEngineView::PrintedPageSizeId::B9)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B10, QQuickWebEngineView::PrintedPageSizeId::B10)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::C5E, QQuickWebEngineView::PrintedPageSizeId::C5E)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Comm10E, QQuickWebEngineView::PrintedPageSizeId::Comm10E)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::DLE, QQuickWebEngineView::PrintedPageSizeId::DLE)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Folio, QQuickWebEngineView::PrintedPageSizeId::Folio)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Ledger, QQuickWebEngineView::PrintedPageSizeId::Ledger)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Tabloid, QQuickWebEngineView::PrintedPageSizeId::Tabloid)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Custom, QQuickWebEngineView::PrintedPageSizeId::Custom)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A3Extra, QQuickWebEngineView::PrintedPageSizeId::A3Extra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A4Extra, QQuickWebEngineView::PrintedPageSizeId::A4Extra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A4Plus, QQuickWebEngineView::PrintedPageSizeId::A4Plus)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A4Small, QQuickWebEngineView::PrintedPageSizeId::A4Small)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::A5Extra, QQuickWebEngineView::PrintedPageSizeId::A5Extra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::B5Extra, QQuickWebEngineView::PrintedPageSizeId::B5Extra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB0, QQuickWebEngineView::PrintedPageSizeId::JisB0)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB1, QQuickWebEngineView::PrintedPageSizeId::JisB1)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB2, QQuickWebEngineView::PrintedPageSizeId::JisB2)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB3, QQuickWebEngineView::PrintedPageSizeId::JisB3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB4, QQuickWebEngineView::PrintedPageSizeId::JisB4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB5, QQuickWebEngineView::PrintedPageSizeId::JisB5)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB6, QQuickWebEngineView::PrintedPageSizeId::JisB6)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB7, QQuickWebEngineView::PrintedPageSizeId::JisB7)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB8, QQuickWebEngineView::PrintedPageSizeId::JisB8)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB9, QQuickWebEngineView::PrintedPageSizeId::JisB9)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::JisB10, QQuickWebEngineView::PrintedPageSizeId::JisB10)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::AnsiC, QQuickWebEngineView::PrintedPageSizeId::AnsiC)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::AnsiD, QQuickWebEngineView::PrintedPageSizeId::AnsiD)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::AnsiE, QQuickWebEngineView::PrintedPageSizeId::AnsiE)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::LegalExtra, QQuickWebEngineView::PrintedPageSizeId::LegalExtra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::LetterExtra, QQuickWebEngineView::PrintedPageSizeId::LetterExtra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::LetterPlus, QQuickWebEngineView::PrintedPageSizeId::LetterPlus)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::LetterSmall, QQuickWebEngineView::PrintedPageSizeId::LetterSmall)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::TabloidExtra, QQuickWebEngineView::PrintedPageSizeId::TabloidExtra)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::ArchA, QQuickWebEngineView::PrintedPageSizeId::ArchA)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::ArchB, QQuickWebEngineView::PrintedPageSizeId::ArchB)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::ArchC, QQuickWebEngineView::PrintedPageSizeId::ArchC)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::ArchD, QQuickWebEngineView::PrintedPageSizeId::ArchD)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::ArchE, QQuickWebEngineView::PrintedPageSizeId::ArchE)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial7x9, QQuickWebEngineView::PrintedPageSizeId::Imperial7x9)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial8x10, QQuickWebEngineView::PrintedPageSizeId::Imperial8x10)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial9x11, QQuickWebEngineView::PrintedPageSizeId::Imperial9x11)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial9x12, QQuickWebEngineView::PrintedPageSizeId::Imperial9x12)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial10x11, QQuickWebEngineView::PrintedPageSizeId::Imperial10x11)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial10x13, QQuickWebEngineView::PrintedPageSizeId::Imperial10x13)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial10x14, QQuickWebEngineView::PrintedPageSizeId::Imperial10x14)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial12x11, QQuickWebEngineView::PrintedPageSizeId::Imperial12x11)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Imperial15x11, QQuickWebEngineView::PrintedPageSizeId::Imperial15x11)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::ExecutiveStandard, QQuickWebEngineView::PrintedPageSizeId::ExecutiveStandard)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Note, QQuickWebEngineView::PrintedPageSizeId::Note)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Quarto, QQuickWebEngineView::PrintedPageSizeId::Quarto)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Statement, QQuickWebEngineView::PrintedPageSizeId::Statement)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::SuperA, QQuickWebEngineView::PrintedPageSizeId::SuperA)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::SuperB, QQuickWebEngineView::PrintedPageSizeId::SuperB)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Postcard, QQuickWebEngineView::PrintedPageSizeId::Postcard)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::DoublePostcard, QQuickWebEngineView::PrintedPageSizeId::DoublePostcard)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Prc16K, QQuickWebEngineView::PrintedPageSizeId::Prc16K)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Prc32K, QQuickWebEngineView::PrintedPageSizeId::Prc32K)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Prc32KBig, QQuickWebEngineView::PrintedPageSizeId::Prc32KBig)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::FanFoldUS, QQuickWebEngineView::PrintedPageSizeId::FanFoldUS)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::FanFoldGerman, QQuickWebEngineView::PrintedPageSizeId::FanFoldGerman)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::FanFoldGermanLegal, QQuickWebEngineView::PrintedPageSizeId::FanFoldGermanLegal)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeB4, QQuickWebEngineView::PrintedPageSizeId::EnvelopeB4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeB5, QQuickWebEngineView::PrintedPageSizeId::EnvelopeB5)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeB6, QQuickWebEngineView::PrintedPageSizeId::EnvelopeB6)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC0, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC0)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC1, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC1)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC2, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC2)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC3, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC4, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC6, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC6)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC65, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC65)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC7, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC7)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Envelope9, QQuickWebEngineView::PrintedPageSizeId::Envelope9)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Envelope11, QQuickWebEngineView::PrintedPageSizeId::Envelope11)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Envelope12, QQuickWebEngineView::PrintedPageSizeId::Envelope12)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Envelope14, QQuickWebEngineView::PrintedPageSizeId::Envelope14)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeMonarch, QQuickWebEngineView::PrintedPageSizeId::EnvelopeMonarch)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePersonal, QQuickWebEngineView::PrintedPageSizeId::EnvelopePersonal)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeChou3, QQuickWebEngineView::PrintedPageSizeId::EnvelopeChou3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeChou4, QQuickWebEngineView::PrintedPageSizeId::EnvelopeChou4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeInvite, QQuickWebEngineView::PrintedPageSizeId::EnvelopeInvite)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeItalian, QQuickWebEngineView::PrintedPageSizeId::EnvelopeItalian)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeKaku2, QQuickWebEngineView::PrintedPageSizeId::EnvelopeKaku2)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeKaku3, QQuickWebEngineView::PrintedPageSizeId::EnvelopeKaku3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc1, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc1)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc2, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc2)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc3, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc3)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc4, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc5, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc5)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc6, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc6)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc7, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc7)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc8, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc8)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc9, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc9)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopePrc10, QQuickWebEngineView::PrintedPageSizeId::EnvelopePrc10)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeYou4, QQuickWebEngineView::PrintedPageSizeId::EnvelopeYou4)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::LastPageSize, QQuickWebEngineView::PrintedPageSizeId::LastPageSize)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::AnsiA, QQuickWebEngineView::PrintedPageSizeId::AnsiA)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::AnsiB, QQuickWebEngineView::PrintedPageSizeId::AnsiB)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeC5, QQuickWebEngineView::PrintedPageSizeId::EnvelopeC5)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::EnvelopeDL, QQuickWebEngineView::PrintedPageSizeId::EnvelopeDL)
+ASSERT_ENUMS_MATCH(QPageSize::PageSizeId::Envelope10, QQuickWebEngineView::PrintedPageSizeId::Envelope10)
+#endif
+
class WebEngineQuickWidgetDelegate : public QtWebEngineCore::WidgetDelegate
{
public:
@@ -359,6 +492,10 @@ static QQuickWebEngineView::Feature toFeature(QtWebEngineCore::ProfileAdapter::P
return QQuickWebEngineView::Notifications;
case QtWebEngineCore::ProfileAdapter::GeolocationPermission:
return QQuickWebEngineView::Geolocation;
+ case QtWebEngineCore::ProfileAdapter::ClipboardReadWrite:
+ return QQuickWebEngineView::ClipboardReadWrite;
+ case QtWebEngineCore::ProfileAdapter::LocalFontsPermission:
+ return QQuickWebEngineView::LocalFontsAccess;
default:
break;
}
@@ -577,6 +714,15 @@ void QQuickWebEngineViewPrivate::windowCloseRejected()
QMetaObject::invokeMethod(q, "windowCloseRejected");
}
+void QQuickWebEngineViewPrivate::desktopMediaRequested(
+ QtWebEngineCore::DesktopMediaController *controller)
+{
+ Q_Q(QQuickWebEngineView);
+ QTimer::singleShot(0, q, [q, controller]() {
+ Q_EMIT q->desktopMediaRequested(QWebEngineDesktopMediaRequest(controller));
+ });
+}
+
void QQuickWebEngineViewPrivate::requestFullScreenMode(const QUrl &origin, bool fullscreen)
{
Q_Q(QQuickWebEngineView);
@@ -592,7 +738,7 @@ bool QQuickWebEngineViewPrivate::isFullScreenMode() const
void QQuickWebEngineViewPrivate::javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString& message, int lineNumber, const QString& sourceID)
{
Q_Q(QQuickWebEngineView);
- if (q->receivers(SIGNAL(javaScriptConsoleMessage(JavaScriptConsoleMessageLevel,QString,int,QString))) > 0) {
+ if (q->receivers(SIGNAL(javaScriptConsoleMessage(QQuickWebEngineView::JavaScriptConsoleMessageLevel,QString,int,QString))) > 0) {
Q_EMIT q->javaScriptConsoleMessage(static_cast<QQuickWebEngineView::JavaScriptConsoleMessageLevel>(level), message, lineNumber, sourceID);
return;
}
@@ -789,6 +935,8 @@ QQuickWebEngineView::QQuickWebEngineView(QQuickItem *parent)
QQuickWebEngineView::~QQuickWebEngineView()
{
+ if (hasFocus())
+ setFocus(false);
}
void QQuickWebEngineViewPrivate::ensureContentsAdapter()
@@ -1305,6 +1453,12 @@ void QQuickWebEngineViewPrivate::hideTouchSelectionMenu()
ui()->hideTouchSelectionMenu();
}
+void QQuickWebEngineViewPrivate::showWebAuthDialog(QWebEngineWebAuthUxRequest *request)
+{
+ Q_Q(QQuickWebEngineView);
+ Q_EMIT q->webAuthUxRequested(request);
+}
+
bool QQuickWebEngineView::isLoading() const
{
Q_D(const QQuickWebEngineView);
@@ -1346,7 +1500,11 @@ void QQuickWebEngineView::runJavaScript(const QString &script, quint32 worldId,
d->ensureContentsAdapter();
if (!callback.isUndefined()) {
quint64 requestId = d_ptr->adapter->runJavaScriptCallbackResult(script, worldId);
- d->m_callbacks.insert(requestId, callback);
+ if (requestId) {
+ d->m_callbacks.insert(requestId, callback);
+ } else {
+ callback.call();
+ }
} else
d->adapter->runJavaScript(script, worldId);
}
@@ -1563,6 +1721,12 @@ QQuickWebEngineView *QQuickWebEngineView::devToolsView() const
return d->devToolsView;
}
+QString QQuickWebEngineView::devToolsId()
+{
+ Q_D(QQuickWebEngineView);
+ d->ensureContentsAdapter();
+ return d->adapter->devToolsId();
+}
void QQuickWebEngineView::setDevToolsView(QQuickWebEngineView *devToolsView)
{
@@ -1621,6 +1785,15 @@ void QQuickWebEngineView::grantFeaturePermission(const QUrl &securityOrigin, QQu
d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::NotificationPermission,
granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission);
break;
+ case ClipboardReadWrite:
+ d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::ClipboardReadWrite,
+ granted ? ProfileAdapter::AllowedPermission
+ : ProfileAdapter::DeniedPermission);
+ break;
+ case LocalFontsAccess:
+ d_ptr->adapter->grantFeaturePermission(securityOrigin, ProfileAdapter::LocalFontsPermission,
+ granted ? ProfileAdapter::AllowedPermission : ProfileAdapter::DeniedPermission);
+ break;
default:
Q_UNREACHABLE();
}
@@ -1969,8 +2142,15 @@ void QQuickWebEngineView::triggerWebAction(WebAction action)
case InsertUnorderedList:
runJavaScript(QStringLiteral("document.execCommand('insertUnorderedList');"), QWebEngineScript::ApplicationWorld);
break;
+ case ChangeTextDirectionLTR:
+ d->adapter->changeTextDirection(true /*left to right*/);
+ break;
+ case ChangeTextDirectionRTL:
+ d->adapter->changeTextDirection(false /*left to right*/);
+ break;
default:
- Q_UNREACHABLE();
+ // Reachable when a spell checker replacement word has been selected
+ break;
}
}
@@ -1984,165 +2164,113 @@ QQuickWebEngineAction *QQuickWebEngineView::action(WebAction action)
return d->actions[action];
}
- QString text;
+ const QString text = QWebEnginePagePrivate::actionText(action);
QString iconName;
switch (action) {
case Back:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Back);
iconName = QStringLiteral("go-previous");
break;
case Forward:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Forward);
iconName = QStringLiteral("go-next");
break;
case Stop:
- text = tr("Stop");
iconName = QStringLiteral("process-stop");
break;
case Reload:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Reload);
iconName = QStringLiteral("view-refresh");
break;
case ReloadAndBypassCache:
- text = tr("Reload and Bypass Cache");
iconName = QStringLiteral("view-refresh");
break;
case Cut:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Cut);
iconName = QStringLiteral("edit-cut");
break;
case Copy:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Copy);
iconName = QStringLiteral("edit-copy");
break;
case Paste:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Paste);
iconName = QStringLiteral("edit-paste");
break;
case Undo:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Undo);
iconName = QStringLiteral("edit-undo");
break;
case Redo:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::Redo);
iconName = QStringLiteral("edit-redo");
break;
case SelectAll:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SelectAll);
iconName = QStringLiteral("edit-select-all");
break;
case PasteAndMatchStyle:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::PasteAndMatchStyle);
iconName = QStringLiteral("edit-paste");
break;
case OpenLinkInThisWindow:
- text = tr("Open link in this window");
- break;
case OpenLinkInNewWindow:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewWindow);
- break;
case OpenLinkInNewTab:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::OpenLinkInNewTab);
- break;
case CopyLinkToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyLinkToClipboard);
- break;
case DownloadLinkToDisk:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadLinkToDisk);
- break;
case CopyImageToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageToClipboard);
- break;
case CopyImageUrlToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyImageUrlToClipboard);
- break;
case DownloadImageToDisk:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadImageToDisk);
- break;
case CopyMediaUrlToClipboard:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::CopyMediaUrlToClipboard);
- break;
case ToggleMediaControls:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaControls);
- break;
case ToggleMediaLoop:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ToggleMediaLoop);
break;
case ToggleMediaPlayPause:
- text = tr("Toggle Play/Pause");
iconName = QStringLiteral("media-playback-start");
break;
case ToggleMediaMute:
- text = tr("Toggle Mute");
iconName = QStringLiteral("audio-volume-muted");
break;
case DownloadMediaToDisk:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::DownloadMediaToDisk);
- break;
case InspectElement:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::InspectElement);
break;
case ExitFullScreen:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ExitFullScreen);
iconName = QStringLiteral("view-fullscreen");
break;
case RequestClose:
- text = tr("Close Page");
iconName = QStringLiteral("window-close");
break;
case Unselect:
- text = tr("Unselect");
iconName = QStringLiteral("edit-select-none");
break;
case SavePage:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::SavePage);
iconName = QStringLiteral("document-save");
break;
+ case OpenLinkInNewBackgroundTab:
+ break;
case ViewSource:
- text = RenderViewContextMenuQt::getMenuItemName(RenderViewContextMenuQt::ContextMenuItem::ViewSource);
break;
case ToggleBold:
- text = tr("&Bold");
iconName = QStringLiteral("format-text-bold");
break;
case ToggleItalic:
- text = tr("&Italic");
iconName = QStringLiteral("format-text-italic");
break;
case ToggleUnderline:
- text = tr("&Underline");
iconName = QStringLiteral("format-text-underline");
break;
case ToggleStrikethrough:
- text = tr("&Strikethrough");
iconName = QStringLiteral("format-text-strikethrough");
break;
case AlignLeft:
- text = tr("Align &Left");
break;
case AlignCenter:
- text = tr("Align &Center");
break;
case AlignRight:
- text = tr("Align &Right");
break;
case AlignJustified:
- text = tr("Align &Justified");
break;
case Indent:
- text = tr("&Indent");
iconName = QStringLiteral("format-indent-more");
break;
case Outdent:
- text = tr("&Outdent");
iconName = QStringLiteral("format-indent-less");
break;
case InsertOrderedList:
- text = tr("Insert &Ordered List");
- break;
case InsertUnorderedList:
- text = tr("Insert &Unordered List");
+ case ChangeTextDirectionLTR:
+ case ChangeTextDirectionRTL:
break;
case NoWebAction:
case WebActionCount:
@@ -2325,6 +2453,8 @@ void QQuickContextMenuBuilder::addMenuItem(ContextMenuItem menuItem)
action = new QQuickWebEngineAction(m_menu);
QString replacement = m_contextData->spellCheckerSuggestions().at(i);
QObject::connect(action, &QQuickWebEngineAction::triggered, [thisRef, replacement] { thisRef->replaceMisspelledWord(replacement); });
+ action->d_ptr->m_text = replacement;
+ action->d_ptr->m_enabled = true;
m_view->d_ptr->ui()->addMenuItem(action, m_menu);
}
return;
@@ -2399,6 +2529,13 @@ QQmlComponent *QQuickWebEngineView::touchHandleDelegate() const
return d_ptr->m_touchHandleDelegate;
}
+void QQuickWebEngineView::save(const QString &filePath,
+ QWebEngineDownloadRequest::SavePageFormat format) const
+{
+ Q_D(const QQuickWebEngineView);
+ d->adapter->save(filePath, format);
+}
+
QT_END_NAMESPACE
#include "moc_qquickwebengineview_p.cpp"
diff --git a/src/webenginequick/api/qquickwebengineview_p.h b/src/webenginequick/api/qquickwebengineview_p.h
index 906e7c3fd..0fdd9f787 100644
--- a/src/webenginequick/api/qquickwebengineview_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p.h
@@ -17,6 +17,8 @@
#include <QtWebEngineCore/qtwebenginecoreglobal.h>
#include <QtWebEngineCore/qwebenginequotarequest.h>
+#include <QtWebEngineCore/qwebenginedesktopmediarequest.h>
+#include <QtWebEngineCore/qwebenginedownloadrequest.h>
#include <QtWebEngineQuick/private/qtwebenginequickglobal_p.h>
#include <QtGui/qcolor.h>
#include <QtQml/qqmlregistration.h>
@@ -50,8 +52,9 @@ class QWebEngineNewWindowRequest;
class QWebEngineRegisterProtocolHandlerRequest;
class QQuickWebEngineScriptCollection;
class QQuickWebEngineTouchSelectionMenuRequest;
+class QWebEngineWebAuthUxRequest;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineView : public QQuickItem {
Q_OBJECT
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
Q_PROPERTY(QUrl url READ url WRITE setUrl NOTIFY urlChanged FINAL)
@@ -80,6 +83,7 @@ class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
Q_PROPERTY(QQuickWebEngineView *inspectedView READ inspectedView WRITE setInspectedView NOTIFY inspectedViewChanged REVISION(1,7) FINAL)
Q_PROPERTY(QQuickWebEngineView *devToolsView READ devToolsView WRITE setDevToolsView NOTIFY devToolsViewChanged REVISION(1,7) FINAL)
+ Q_PROPERTY(QString devToolsId READ devToolsId CONSTANT REVISION(6,6) FINAL)
Q_PROPERTY(LifecycleState lifecycleState READ lifecycleState WRITE setLifecycleState NOTIFY lifecycleStateChanged REVISION(1,10) FINAL)
Q_PROPERTY(LifecycleState recommendedState READ recommendedState NOTIFY recommendedStateChanged REVISION(1,10) FINAL)
@@ -169,6 +173,8 @@ QT_WARNING_POP
DesktopVideoCapture,
DesktopAudioVideoCapture,
Notifications,
+ ClipboardReadWrite,
+ LocalFontsAccess,
};
Q_ENUM(Feature)
@@ -212,6 +218,7 @@ QT_WARNING_POP
RequestClose,
Unselect,
SavePage,
+ OpenLinkInNewBackgroundTab, // Not supported in QML
ViewSource,
ToggleBold,
@@ -229,6 +236,9 @@ QT_WARNING_POP
InsertOrderedList,
InsertUnorderedList,
+ ChangeTextDirectionLTR,
+ ChangeTextDirectionRTL,
+
WebActionCount
};
Q_ENUM(WebAction)
@@ -260,8 +270,6 @@ QT_WARNING_POP
// must match QPageSize::PageSizeId
enum PrintedPageSizeId {
// Existing Qt sizes
- A4,
- B5,
Letter,
Legal,
Executive,
@@ -269,21 +277,24 @@ QT_WARNING_POP
A1,
A2,
A3,
+ A4,
A5,
A6,
A7,
A8,
A9,
+ A10,
B0,
B1,
- B10,
B2,
B3,
B4,
+ B5,
B6,
B7,
B8,
B9,
+ B10,
C5E,
Comm10E,
DLE,
@@ -293,7 +304,6 @@ QT_WARNING_POP
Custom,
// New values derived from PPD standard
- A10,
A3Extra,
A4Extra,
A4Plus,
@@ -396,10 +406,8 @@ QT_WARNING_POP
EnvelopePrc10,
EnvelopeYou4,
- // Last item, with commonly used synynoms from QPagedPrintEngine / QPrinter
+ // Last item
LastPageSize = EnvelopeYou4,
- NPageSize = LastPageSize,
- NPaperSize = LastPageSize,
// Convenience overloads for naming consistency
AnsiA = Letter,
@@ -454,6 +462,7 @@ QT_WARNING_POP
QQuickWebEngineView *inspectedView() const;
void setDevToolsView(QQuickWebEngineView *);
QQuickWebEngineView *devToolsView() const;
+ QString devToolsId();
LifecycleState lifecycleState() const;
void setLifecycleState(LifecycleState state);
@@ -475,12 +484,15 @@ public Q_SLOTS:
void stop();
Q_REVISION(1,1) void findText(const QString &subString, FindFlags options = { }, const QJSValue &callback = QJSValue());
Q_REVISION(1,1) void fullScreenCancelled();
- Q_REVISION(1,1) void grantFeaturePermission(const QUrl &securityOrigin, Feature, bool granted);
+ Q_REVISION(1,1) void grantFeaturePermission(const QUrl &securityOrigin, QQuickWebEngineView::Feature, bool granted);
Q_REVISION(1,2) void setActiveFocusOnPress(bool arg);
Q_REVISION(1,2) void triggerWebAction(WebAction action);
Q_REVISION(1,3) void printToPdf(const QString &filePath, PrintedPageSizeId pageSizeId = PrintedPageSizeId::A4, PrintedPageOrientation orientation = PrintedPageOrientation::Portrait);
Q_REVISION(1,3) void printToPdf(const QJSValue &callback, PrintedPageSizeId pageSizeId = PrintedPageSizeId::A4, PrintedPageOrientation orientation = PrintedPageOrientation::Portrait);
Q_REVISION(1,4) void replaceMisspelledWord(const QString &replacement);
+ Q_REVISION(6, 6) void save(const QString &filePath,
+ QWebEngineDownloadRequest::SavePageFormat format =
+ QWebEngineDownloadRequest::MimeHtmlSaveFormat) const;
private Q_SLOTS:
void lazyInitialize();
@@ -493,17 +505,22 @@ Q_SIGNALS:
void loadProgressChanged();
void linkHovered(const QUrl &hoveredUrl);
void navigationRequested(QWebEngineNavigationRequest *request);
- void javaScriptConsoleMessage(JavaScriptConsoleMessageLevel level, const QString &message, int lineNumber, const QString &sourceID);
+ void javaScriptConsoleMessage(QQuickWebEngineView::JavaScriptConsoleMessageLevel level,
+ const QString &message, int lineNumber, const QString &sourceID);
Q_REVISION(1,1) void certificateError(const QWebEngineCertificateError &error);
Q_REVISION(1,1) void fullScreenRequested(const QWebEngineFullScreenRequest &request);
Q_REVISION(1,1) void isFullScreenChanged();
- Q_REVISION(1,1) void featurePermissionRequested(const QUrl &securityOrigin, Feature feature);
+ Q_REVISION(1, 1)
+ void featurePermissionRequested(const QUrl &securityOrigin,
+ QQuickWebEngineView::Feature feature);
Q_REVISION(1,1) void zoomFactorChanged(qreal arg);
Q_REVISION(1,1) void profileChanged();
Q_REVISION(1,1) void webChannelChanged();
Q_REVISION(1,2) void activeFocusOnPressChanged(bool);
Q_REVISION(1,2) void backgroundColorChanged();
- Q_REVISION(1,2) void renderProcessTerminated(RenderProcessTerminationStatus terminationStatus, int exitCode);
+ Q_REVISION(1, 2)
+ void renderProcessTerminated(QQuickWebEngineView::RenderProcessTerminationStatus terminationStatus,
+ int exitCode);
Q_REVISION(1,2) void windowCloseRequested();
Q_REVISION(1,3) void contentsSizeChanged(const QSizeF& size);
Q_REVISION(1,3) void scrollPositionChanged(const QPointF& position);
@@ -527,8 +544,8 @@ Q_SIGNALS:
Q_REVISION(1,8) void printRequested();
Q_REVISION(1,9) void selectClientCertificate(QQuickWebEngineClientCertificateSelection *clientCertSelection);
Q_REVISION(1,10) void tooltipRequested(QQuickWebEngineTooltipRequest *request);
- Q_REVISION(1,10) void lifecycleStateChanged(LifecycleState state);
- Q_REVISION(1,10) void recommendedStateChanged(LifecycleState state);
+ Q_REVISION(1, 10) void lifecycleStateChanged(QQuickWebEngineView::LifecycleState state);
+ Q_REVISION(1, 10) void recommendedStateChanged(QQuickWebEngineView::LifecycleState state);
Q_REVISION(1,10) void findTextFinished(const QWebEngineFindTextResult &result);
Q_REVISION(1,11) void renderProcessPidChanged(qint64 pid);
Q_REVISION(1,11) void canGoBackChanged();
@@ -537,6 +554,8 @@ Q_SIGNALS:
Q_REVISION(6,3) void touchSelectionMenuRequested(QQuickWebEngineTouchSelectionMenuRequest *request);
Q_REVISION(6,4) void touchHandleDelegateChanged();
Q_REVISION(6,4) void fileSystemAccessRequested(const QWebEngineFileSystemAccessRequest &request);
+ Q_REVISION(6, 7) void webAuthUxRequested(QWebEngineWebAuthUxRequest *request);
+ Q_REVISION(6,7) void desktopMediaRequested(const QWebEngineDesktopMediaRequest &request);
protected:
void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/webenginequick/api/qquickwebengineview_p_p.h b/src/webenginequick/api/qquickwebengineview_p_p.h
index aa67fd291..66e53bdd0 100644
--- a/src/webenginequick/api/qquickwebengineview_p_p.h
+++ b/src/webenginequick/api/qquickwebengineview_p_p.h
@@ -19,7 +19,7 @@
#include "qquickwebengineview_p.h"
#include "render_view_context_menu_qt.h"
#include "touch_handle_drawable_client.h"
-#include "ui_delegates_manager.h"
+#include "ui_delegates_manager_p.h"
#include "web_contents_adapter_client.h"
#include <QtCore/qcompilerdetection.h>
@@ -45,7 +45,7 @@ class QWebEngineContextMenuRequest;
class QWebEngineFindTextResult;
class QWebEngineHistory;
-class Q_WEBENGINEQUICK_PRIVATE_EXPORT QQuickWebEngineViewPrivate : public QtWebEngineCore::WebContentsAdapterClient
+class Q_WEBENGINEQUICK_EXPORT QQuickWebEngineViewPrivate : public QtWebEngineCore::WebContentsAdapterClient
{
public:
Q_DECLARE_PUBLIC(QQuickWebEngineView)
@@ -91,6 +91,7 @@ public:
void navigationRequested(int navigationType, const QUrl &url, bool &accepted, bool isMainFrame) override;
void javascriptDialog(QSharedPointer<QtWebEngineCore::JavaScriptDialogController>) override;
void runFileChooser(QSharedPointer<QtWebEngineCore::FilePickerController>) override;
+ void desktopMediaRequested(QtWebEngineCore::DesktopMediaController *) override;
void showColorDialog(QSharedPointer<QtWebEngineCore::ColorChooserController>) override;
void didRunJavaScript(quint64, const QVariant&) override;
void didFetchDocumentMarkup(quint64, const QString&) override { }
@@ -132,6 +133,7 @@ public:
void showAutofillPopup(QtWebEngineCore::AutofillPopupController *controller,
const QRect &bounds, bool autoselectFirstSuggestion) override;
void hideAutofillPopup() override;
+ void showWebAuthDialog(QWebEngineWebAuthUxRequest *request) override;
void updateAction(QQuickWebEngineView::WebAction) const;
bool adoptWebContents(QtWebEngineCore::WebContentsAdapter *webContents);
diff --git a/src/webenginequick/api/qtwebenginequickglobal.cpp b/src/webenginequick/api/qtwebenginequickglobal.cpp
index b16305dae..e24ef643b 100644
--- a/src/webenginequick/api/qtwebenginequickglobal.cpp
+++ b/src/webenginequick/api/qtwebenginequickglobal.cpp
@@ -37,18 +37,22 @@ namespace QtWebEngineQuick {
*/
void initialize()
{
+ auto api = QQuickWindow::graphicsApi();
if (!QCoreApplication::startingUp()) {
- qWarning("QtWebEngineQuick::initialize() called with QCoreApplication object already created and should be call before. "\
- "This is depreciated and may fail in the future.");
+ if (api == QSGRendererInterface::OpenGL || (api != QSGRendererInterface::Vulkan
+ && api != QSGRendererInterface::Metal && api != QSGRendererInterface::Direct3D11)) {
+ qWarning("QtWebEngineQuick::initialize() called with QCoreApplication object already created and should be call before. "\
+ "This is depreciated and may fail in the future.");
+ }
QtWebEngineCore::initialize();
return;
}
// call initialize the same way as widgets do
qAddPreRoutine(QtWebEngineCore::initialize);
- auto api = QQuickWindow::graphicsApi();
- if (api != QSGRendererInterface::OpenGLRhi && api != QSGRendererInterface::VulkanRhi)
- QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGLRhi);
+ if (api != QSGRendererInterface::OpenGL && api != QSGRendererInterface::Vulkan
+ && api != QSGRendererInterface::Metal && api != QSGRendererInterface::Direct3D11)
+ QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL);
}
} // namespace QtWebEngineQuick
diff --git a/src/webenginequick/api/qtwebenginequickglobal_p.h b/src/webenginequick/api/qtwebenginequickglobal_p.h
index 395533604..256bcd590 100644
--- a/src/webenginequick/api/qtwebenginequickglobal_p.h
+++ b/src/webenginequick/api/qtwebenginequickglobal_p.h
@@ -19,10 +19,4 @@
#include <QtCore/private/qglobal_p.h>
#include <QtWebEngineQuick/private/qtwebenginequick-config_p.h>
-QT_BEGIN_NAMESPACE
-
-#define Q_WEBENGINEQUICK_PRIVATE_EXPORT Q_WEBENGINEQUICK_EXPORT
-
-QT_END_NAMESPACE
-
#endif // QTWEBENGINEQUICKGLOBAL_P_H
diff --git a/src/webenginequick/doc/snippets/minimal/main.cpp b/src/webenginequick/doc/snippets/minimal/main.cpp
new file mode 100644
index 000000000..e17493a36
--- /dev/null
+++ b/src/webenginequick/doc/snippets/minimal/main.cpp
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [Minimal Example]
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+#include <QtWebEngineQuick/qtwebenginequickglobal.h>
+
+int main(int argc, char *argv[])
+{
+ QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
+ QtWebEngineQuick::initialize();
+ QGuiApplication app(argc, argv);
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
+ return app.exec();
+}
+//! [Minimal Example]
diff --git a/src/webenginequick/doc/snippets/minimal/main.qml b/src/webenginequick/doc/snippets/minimal/main.qml
new file mode 100644
index 000000000..87a8757df
--- /dev/null
+++ b/src/webenginequick/doc/snippets/minimal/main.qml
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+//! [Minimal Example]
+import QtQuick
+import QtQuick.Window
+import QtWebEngine
+
+Window {
+ width: 1024
+ height: 750
+ visible: true
+ WebEngineView {
+ anchors.fill: parent
+ url: "https://www.qt.io"
+ }
+}
+//! [Minimal Example]
diff --git a/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc b/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc
index 76dea97cf..f8fbbd669 100644
--- a/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc
+++ b/src/webenginequick/doc/snippets/qtwebengine_build_snippet.qdoc
@@ -7,5 +7,5 @@ QT += webenginequick
//! [2]
find_package(Qt6 REQUIRED COMPONENTS WebEngineQuick)
-target_link_libraries(target PRIVATE Qt::WebEngineQuick)
+target_link_libraries(target PRIVATE Qt6::WebEngineQuick)
//! [2]
diff --git a/src/webenginequick/doc/snippets/qtwebengine_webengineaction.qml b/src/webenginequick/doc/snippets/qtwebengine_webengineaction.qml
new file mode 100644
index 000000000..2fd5f490b
--- /dev/null
+++ b/src/webenginequick/doc/snippets/qtwebengine_webengineaction.qml
@@ -0,0 +1,123 @@
+// Copyright (C) 2018 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Window
+import QtWebEngine
+import QtQuick.Controls
+import QtQuick.Layouts
+
+ApplicationWindow {
+ id: window
+ visible: true
+ width: 800
+ height: 600
+ title: qsTr("WebEngineAction Example")
+
+ header: ToolBar {
+ RowLayout {
+ anchors.fill: parent
+//! [0]
+ ToolButton {
+ property int itemAction: WebEngineView.Back
+ text: webEngineView.action(itemAction).text
+ enabled: webEngineView.action(itemAction).enabled
+ onClicked: webEngineView.action(itemAction).trigger()
+ icon.name: webEngineView.action(itemAction).iconName
+ display: AbstractButton.TextUnderIcon
+ }
+//! [0]
+ ToolButton {
+ property int itemAction: WebEngineView.Forward
+ text: webEngineView.action(itemAction).text
+ enabled: webEngineView.action(itemAction).enabled
+ onClicked: webEngineView.action(itemAction).trigger()
+ icon.name: webEngineView.action(itemAction).iconName
+ display: AbstractButton.TextUnderIcon
+ }
+
+ ToolButton {
+ property int itemAction: webEngineView.loading ? WebEngineView.Stop : WebEngineView.Reload
+ text: webEngineView.action(itemAction).text
+ enabled: webEngineView.action(itemAction).enabled
+ onClicked: webEngineView.action(itemAction).trigger()
+ icon.name: webEngineView.action(itemAction).iconName
+ display: AbstractButton.TextUnderIcon
+ }
+
+ TextField {
+ Layout.fillWidth: true
+
+ text: webEngineView.url
+ selectByMouse: true
+ onEditingFinished: webEngineView.url = utils.fromUserInput(text)
+ }
+
+ ToolButton {
+ id: settingsButton
+ text: "Settings"
+ icon.name: "settings-configure"
+ display: AbstractButton.TextUnderIcon
+ onClicked: settingsMenu.open()
+ checked: settingsMenu.visible
+
+ Menu {
+ id: settingsMenu
+ y: settingsButton.height
+
+ MenuItem {
+ id: customContextMenuOption
+ checkable: true
+ checked: true
+
+ text: "Custom context menu"
+ }
+ }
+ }
+ }
+ }
+
+ WebEngineView {
+ id: webEngineView
+ url: "https://qt.io"
+ anchors.fill: parent
+
+ Component.onCompleted: {
+ profile.downloadRequested.connect(function(download){
+ download.accept();
+ })
+ }
+
+//! [1]
+ property Menu contextMenu: Menu {
+ Repeater {
+ model: [
+ WebEngineView.Back,
+ WebEngineView.Forward,
+ WebEngineView.Reload,
+ WebEngineView.SavePage,
+ WebEngineView.Copy,
+ WebEngineView.Paste,
+ WebEngineView.Cut,
+ WebEngineView.ChangeTextDirectionLTR,
+ WebEngineView.ChangeTextDirectionRTL,
+ ]
+ MenuItem {
+ text: webEngineView.action(modelData).text
+ enabled: webEngineView.action(modelData).enabled
+ onClicked: webEngineView.action(modelData).trigger()
+ icon.name: webEngineView.action(modelData).iconName
+ display: MenuItem.TextBesideIcon
+ }
+ }
+ }
+
+ onContextMenuRequested: function(request) {
+ if (customContextMenuOption.checked) {
+ request.accepted = true;
+ contextMenu.popup();
+ }
+ }
+//! [1]
+ }
+}
diff --git a/src/webenginequick/doc/src/qtwebengine-examples.qdoc b/src/webenginequick/doc/src/qtwebengine-examples.qdoc
index b3eb548e5..eebf18ba1 100644
--- a/src/webenginequick/doc/src/qtwebengine-examples.qdoc
+++ b/src/webenginequick/doc/src/qtwebengine-examples.qdoc
@@ -5,7 +5,6 @@
\group webengine-examples
\title Qt WebEngine Quick Examples
\brief Examples demonstrating the \QWE usage.
- \ingroup all-examples
These examples and demonstrations show a range of different uses for \l{Qt WebEngine},
from displaying Web pages within a QML user interface to an implementation of
diff --git a/src/webenginequick/doc/src/qtwebengine-qmlmodule.qdoc b/src/webenginequick/doc/src/qtwebengine-qmlmodule.qdoc
index 19348508c..ecf3a4a6e 100644
--- a/src/webenginequick/doc/src/qtwebengine-qmlmodule.qdoc
+++ b/src/webenginequick/doc/src/qtwebengine-qmlmodule.qdoc
@@ -17,4 +17,13 @@
in the Qt6 package and \c target_link_libraries() to link against the module:
\snippet qtwebengine_build_snippet.qdoc 2
+
+ The minimal amount of code needed to load and display an HTML page using the QML engine
+ requires a proper initialization:
+
+ \snippet minimal/main.cpp Minimal Example
+
+ Where the content of main.qml is simply:
+
+ \snippet minimal/main.qml Minimal Example
*/
diff --git a/src/webenginequick/doc/src/webengine_certificate_error.qdoc b/src/webenginequick/doc/src/webengine_certificate_error.qdoc
index aec8e2d42..93bad9fb1 100644
--- a/src/webenginequick/doc/src/webengine_certificate_error.qdoc
+++ b/src/webenginequick/doc/src/webengine_certificate_error.qdoc
@@ -9,7 +9,7 @@
\brief A utility type for ignoring certificate errors or rejecting erroneous certificates.
- This QML type contains information about a certificate error that occurred. The \l error
+ This QML type contains information about a certificate error that occurred. The \l type
property holds the reason that the error occurred and the \l description property holds a
short localized description of the error. The \l url property holds the URL that triggered
the error.
@@ -49,7 +49,7 @@
The URL that triggered the error.
*/
/*!
- \qmlproperty enumeration WebEngineCertificateError::error
+ \qmlproperty enumeration WebEngineCertificateError::type
\readonly
The type of the error.
diff --git a/src/webenginequick/doc/src/webengineview_lgpl.qdoc b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
index 8848b03e8..eeae34dcc 100644
--- a/src/webenginequick/doc/src/webengineview_lgpl.qdoc
+++ b/src/webenginequick/doc/src/webengineview_lgpl.qdoc
@@ -24,7 +24,7 @@
\l QtWebEngineQuick::initialize in the application main source file, as illustrated by the
following code snippet:
- \quotefromfile webenginequick/minimal/main.cpp
+ \quotefromfile minimal/main.cpp
\skipto main
\printuntil }
@@ -39,7 +39,7 @@
The following sample QML application loads a web page using the \c url property:
- \quotefromfile webenginequick/minimal/main.qml
+ \quotefromfile minimal/main.qml
\skipto import
\printuntil /^\}/
@@ -356,9 +356,8 @@
This method offers a lower-level alternative to the \c{url} property,
which references HTML pages via URL.
- External objects, such as stylesheets or images referenced in the HTML
- document, should be located relative to \a baseUrl. For external objects to
- be loaded, \c baseUrl cannot be empty. For example, if \a html
+ \a baseUrl is optional and used to resolve relative URLs in the document,
+ such as referenced images or stylesheets. For example, if \a html
is retrieved from \c http://www.example.com/documents/overview.html, which
is the base URL, then an image referenced with the relative URL, \c diagram.png,
should be at \c{http://www.example.com/documents/diagram.png}.
@@ -787,6 +786,7 @@
Exit the fullscreen mode. (Added in Qt 5.6)
\value WebEngineView.SavePage
Save the current web page to disk. (Added in Qt 5.7)
+ \omitvalue WebEngineView.OpenLinkInNewBackgroundTab
\value WebEngineView.ViewSource
Show the source of the current page in a new tab. Requires a handler for the
\l newWindowRequested() signal. (Added in Qt 5.8)
@@ -831,6 +831,10 @@
Inserts an unordered list at the current cursor position,
deleting the current selection.
Requires \c contenteditable="true". (Added in Qt 5.10)
+ \value WebEngineView.ChangeTextDirectionLTR
+ Changes text direction to left-to-right in the focused input element. (Added in Qt 6.6)
+ \value WebEngineView.ChangeTextDirectionRTL
+ Changes text direction to right-to-left in the focused input element. (Added in Qt 6.6)
\omitvalue WebActionCount
*/
@@ -848,13 +852,22 @@
Video devices, such as cameras.
\value WebEngineView.MediaAudioVideoCapture
Both audio and video capture devices.
- \value DesktopVideoCapture
+ \value WebEngineView.DesktopVideoCapture
Video output capture, that is, the capture of the user's display.
(Added in Qt 5.10)
- \value DesktopAudioVideoCapture
+ \value WebEngineView.DesktopAudioVideoCapture
Both audio and video output capture. (Added in Qt 5.10)
- \value WebEnginView.Notifications
+ \value WebEngineView.Notifications
Web notifications for the end-user.
+ \value WebEngineView.ClipboardReadWrite
+ Read and write access for the clipboard. If both \l{WebEngineSettings::JavascriptCanPaste}
+ {JavascriptCanPaste} and \l{WebEngineSettings::JavascriptCanAccessClipboard}
+ {JavascriptCanAccessClipboard} settings are enabled, this permission will always be granted
+ automatically and no feature requests will be made.
+ (Added in Qt 6.8)
+ \value WebEngineView.LocalFontsAccess
+ Access to the fonts installed on the user's machine. Only available on desktop platforms.
+ (Added in Qt 6.8)
\sa featurePermissionRequested(), grantFeaturePermission()
*/
@@ -996,8 +1009,6 @@
\value WebEngineView.EnvelopePrc10
\value WebEngineView.EnvelopeYou4
\value WebEngineView.LastPageSize = \c EnvelopeYou4
- \omitvalue NPageSize
- \omitvalue NPaperSize
\sa WebEngineView::printToPdf()
*/
@@ -1300,6 +1311,20 @@
*/
/*!
+ \qmlproperty WebEngineView WebEngineView::devToolsId
+ \since QtWebEngine 6.6
+ \readonly
+
+ The id of the developer tools host associated with this page.
+
+ If remote debugging is enabled (see \l{Qt WebEngine Developer Tools}), the id can be used to
+ build the URL to connect to the developer tool websocket:
+ \c{ws://localhost:<debugggin-port>/devtools/page/<id>)}. The websocket can be used to to interact
+ with the page using the \l{https://chromedevtools.github.io/devtools-protocol/}{DevTools
+ Protocol}.
+*/
+
+/*!
\qmlmethod WebEngineAction WebEngineView::action(WebAction action)
\since 5.12
@@ -1315,10 +1340,11 @@
*/
/*!
- \qmlsignal WebEngineView::printRequest
+ \qmlsignal WebEngineView::printRequested
\since QtWebEngine 1.8
- This signal is emitted when the JavaScript \c{window.print()} method is called.
+ This signal is emitted when the JavaScript \c{window.print()} method is called or the user pressed the print
+ button of PDF viewer plugin.
Typically, the signal handler can simply call printToPdf().
\sa printToPdf
@@ -1501,6 +1527,58 @@
// ...
}
\endcode
+
+ The touch handles can be also switched dynamically:
+
+ \code
+ Component {
+ id: circleTouchHandle
+ Rectangle {
+ color: "blue"
+ radius: 50
+ }
+ }
+ function showDefaultHandle(isDefault) {
+ if (isDefault)
+ webEngineView.touchHandleDelegate = circleTouchHandle
+ else
+ webEngineView.touchHandleDelegate = null
+ }
+ \endcode
+
+ \note If no delegate is provided, Chromium's default touch handles will appear.
+
+*/
+
+/*!
+ \qmlmethod void WebEngineView::save(const QString &filePath, QWebEngineDownloadRequest::SavePageFormat format)
+ \since QtWebEngine 6.6
+
+ Save the current web page to disk.
+
+ The web page is saved to \a filePath in the specified \a{format}.
+
+ This is a shortcut for the following actions:
+ \list
+ \li Trigger the Save web action.
+ \li Accept the next download item and set the specified file path and save format.
+ \endlist
+
+ This function issues an asynchronous download request for the web page and returns immediately.
+
+ \sa QWebEngineDownloadRequest::SavePageFormat
+*/
+
+/*!
+ \qmlsignal WebEngineView::webAuthUxRequested(QWebEngineWebAuthUxRequest *request);
+ \since QtWebEngine 6.7
+
+ This signal is emitted when a WebAuth authenticator requires user interaction
+ during the authentication process. These requests are handled by displaying a dialog to the user.
+
+ The \a request contains the information and API required to complete the WebAuth UX request.
+
+ \sa QWebEngineWebAuthUxRequest
*/
\sa {WebEngine Qt Quick Custom Touch Handle Example}
diff --git a/src/webenginequick/plugin.cpp b/src/webenginequick/plugin.cpp
index d64059a07..e06596b44 100644
--- a/src/webenginequick/plugin.cpp
+++ b/src/webenginequick/plugin.cpp
@@ -9,10 +9,10 @@
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
QT_BEGIN_NAMESPACE
-void Q_WEBENGINEQUICK_PRIVATE_EXPORT qml_register_types_QtWebEngine();
+void Q_WEBENGINEQUICK_EXPORT qml_register_types_QtWebEngine();
QT_END_NAMESPACE
#else
-void Q_WEBENGINEQUICK_PRIVATE_EXPORT qml_register_types_QtWebEngine();
+void Q_WEBENGINEQUICK_EXPORT qml_register_types_QtWebEngine();
#endif
QT_BEGIN_NAMESPACE
diff --git a/src/webenginequick/qquickwebengine_accessible.cpp b/src/webenginequick/qquickwebengine_accessible.cpp
index 2941f01b5..e156a5e8b 100644
--- a/src/webenginequick/qquickwebengine_accessible.cpp
+++ b/src/webenginequick/qquickwebengine_accessible.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qquickwebengine_accessible.h"
+#include "qquickwebengine_accessible_p.h"
#include <QQuickItem>
#include <QQuickWindow>
diff --git a/src/webenginequick/qquickwebengine_accessible.h b/src/webenginequick/qquickwebengine_accessible_p.h
index 479de9789..2f774f898 100644
--- a/src/webenginequick/qquickwebengine_accessible.h
+++ b/src/webenginequick/qquickwebengine_accessible_p.h
@@ -4,6 +4,17 @@
#ifndef QQUICKWEBENGINE_ACCESSIBLE_H
#define QQUICKWEBENGINE_ACCESSIBLE_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/qpointer.h>
#include <QtGui/qaccessibleobject.h>
diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp
index b003dabe4..090b09281 100644
--- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "render_widget_host_view_qt_delegate_quickwindow.h"
+#include "render_widget_host_view_qt_delegate_quickwindow_p.h"
#include "api/qquickwebengineview_p_p.h"
diff --git a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h
index 712eef732..3559bd2f0 100644
--- a/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow.h
+++ b/src/webenginequick/render_widget_host_view_qt_delegate_quickwindow_p.h
@@ -4,6 +4,17 @@
#ifndef RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICKWINDOW_H
#define RENDER_WIDGET_HOST_VIEW_QT_DELEGATE_QUICKWINDOW_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include "render_widget_host_view_qt_delegate.h"
#include "render_widget_host_view_qt_delegate_item.h"
diff --git a/src/webenginequick/ui/AlertDialog.qml b/src/webenginequick/ui/AlertDialog.qml
index 53911f0bc..e4c17b056 100644
--- a/src/webenginequick/ui/AlertDialog.qml
+++ b/src/webenginequick/ui/AlertDialog.qml
@@ -49,6 +49,7 @@ Dialog {
id: message
Layout.fillWidth: true
color: palette.windowText
+ textFormat: Text.PlainText
}
}
Item {
diff --git a/src/webenginequick/ui/AuthenticationDialog.qml b/src/webenginequick/ui/AuthenticationDialog.qml
index f9de8d79f..d0611b84f 100644
--- a/src/webenginequick/ui/AuthenticationDialog.qml
+++ b/src/webenginequick/ui/AuthenticationDialog.qml
@@ -50,6 +50,7 @@ Dialog {
Label {
id: message
color: palette.windowText
+ textFormat: Text.PlainText
}
GridLayout {
columns: 2
diff --git a/src/webenginequick/ui/CMakeLists.txt b/src/webenginequick/ui/CMakeLists.txt
index 96dedf016..ac960535e 100644
--- a/src/webenginequick/ui/CMakeLists.txt
+++ b/src/webenginequick/ui/CMakeLists.txt
@@ -1,11 +1,16 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
+if (Qt6Quick_VERSION VERSION_GREATER_EQUAL "6.4.0")
+set(colorDialog "ColorDialog.qml")
+else()
+set(colorDialog "custom/ColorDialog.qml")
+endif()
+
set(qml_files
"AlertDialog.qml"
"AuthenticationDialog.qml"
"AutofillPopup.qml"
- "ColorDialog.qml"
"ConfirmDialog.qml"
"DirectoryPicker.qml"
"FilePicker.qml"
@@ -16,6 +21,7 @@ set(qml_files
"ToolTip.qml"
"TouchHandle.qml"
"TouchSelectionMenu.qml"
+ ${colorDialog}
)
set(resource_files
@@ -31,6 +37,7 @@ qt_internal_add_qml_module(WebEngineQuickDelegatesQml
NO_SYNC_QT
PLUGIN_TARGET qtwebenginequickdelegatesplugin
DEPENDENCIES QtQuickControls2
+ NO_GENERATE_CPP_EXPORTS
)
qt_internal_add_resource(qtwebenginequickdelegatesplugin "qtwebenginequickdelegatesplugin"
diff --git a/src/webenginequick/ui/ColorDialog.qml b/src/webenginequick/ui/ColorDialog.qml
index 895c90198..f4d5b817b 100644
--- a/src/webenginequick/ui/ColorDialog.qml
+++ b/src/webenginequick/ui/ColorDialog.qml
@@ -1,285 +1,13 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-import QtQuick
-import QtQuick.Controls
-import QtQuick.Layouts
+import QtQuick.Dialogs
-Dialog {
+ColorDialog {
id: colorDialog
- title: qsTr("Color Picker Dialog")
- modal: false
- anchors.centerIn: parent
objectName: "colorDialog"
- property bool handled: false
- property color color
-
signal selectedColor(var color)
- signal rejected()
-
- function accept() {
- handled = true;
- selectedColor(colorDialog.color)
- close();
- }
-
- function reject() {
- handled = true;
- rejected();
- close();
- }
-
- // Handle the case where users simply closes or clicks out of the dialog.
- onVisibleChanged: {
- if (!visible && !handled) {
- handled = true;
- rejected();
- } else {
- handled = false;
- }
- }
-
- function selectColorFromPalette(paletteColor) {
- colorDialog.color = paletteColor;
- }
-
- function zeroPadding(text, length = 2) {
- var textLength = text.length;
-
- if (textLength >= length) {
- return text;
- }
-
- for (var i = 0; i < length - textLength; i++) {
- text = "0" + text;
- }
-
- return text;
- }
-
- function calculateRGBA() {
-
- var rgbArray = [colorDialog.color.r, colorDialog.color.g, colorDialog.color.b]
- if (colorDialog.color.a != 1) {
- rgbArray.push(colorDialog.color.a);
- }
-
- for (var i = 0; i < rgbArray.length; i++) {
- rgbArray[i] = Number(Math.round(rgbArray[i] * 255)).toString(16);
- rgbArray[i] = zeroPadding(rgbArray[i]);
- }
-
- return "#" + rgbArray.join("");
- }
-
-
- function isNaNOrUndefined(value) {
- return value == null || value == undefined || Number.isNaN(value);
- }
-
- function parseColorText(colorText) {
- if (colorText[0] == '#') {
- colorText = colorText.substring(1);
- }
-
- if (!(colorText.length == 6 || colorText.length == 8)) {
- return undefined;
- }
-
- var rgbaValues = [parseInt("0x" + colorText.substring(0,2)),
- parseInt("0x" + colorText.substring(2,4)),
- parseInt("0x" + colorText.substring(4,6)),
- parseInt("0x" + (colorText.length > 6 ? colorText.substring(6,8) : "FF"))]
-
- for (var i = 0; i < rgbaValues.length; i++) {
- if (isNaNOrUndefined(rgbaValues[i])) {
- return undefined;
- }
- rgbaValues[i] = rgbaValues[i] / 255;
- }
-
- return Qt.rgba(rgbaValues[0], rgbaValues[1], rgbaValues[2], rgbaValues[3]);
- }
-
- ListModel {
- id: colorList
- ListElement { rectangleColor: "red" }
- ListElement { rectangleColor: "orangered" }
- ListElement { rectangleColor: "orange" }
- ListElement { rectangleColor: "gold" }
- ListElement { rectangleColor: "yellow" }
- ListElement { rectangleColor: "yellowgreen" }
- ListElement { rectangleColor: "green" }
- ListElement { rectangleColor: "lightskyblue" }
- ListElement { rectangleColor: "blue" }
- ListElement { rectangleColor: "blueviolet" }
- ListElement { rectangleColor: "violet" }
- ListElement { rectangleColor: "mediumvioletred" }
- ListElement { rectangleColor: "black" }
- ListElement { rectangleColor: "white" }
- }
-
- contentItem: GridLayout {
- id: grid
- columns: 7
- rows: 5
-
- Repeater {
- model: colorList
- delegate: Rectangle {
- width: 50
- height: 50
- color: rectangleColor
- border.color: "black"
- border.width: 1
-
- MouseArea {
- anchors.fill: parent
- onClicked: selectColorFromPalette(parent.color)
- }
- }
- }
- ColumnLayout {
- id: colorTools
- Layout.columnSpan: 4
- Layout.rowSpan: 2
- Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
-
- Rectangle {
- height: 100
- width: 200
- border.color: "black"
- border.width: 1
-
- Binding on color {
- when: colorDialog.color
- value: colorDialog.color
- }
- }
- TextField {
- id: colorTextField
- width: 100
- selectByMouse: true
- Layout.alignment: Qt.AlignHCenter
-
- Binding on text {
- when: colorDialog.color
- value: calculateRGBA()
- delayed: true
- }
-
- onTextEdited: {
- var parsedColor = parseColorText(colorTextField.text);
- if (parsedColor != undefined) {
- colorDialog.color = parsedColor;
- }
- }
-
- MouseArea {
- id: colorTextFieldMouseArea
- anchors.fill: parent
- acceptedButtons: Qt.RightButton
- onClicked: colorTextFieldContextMenu.open()
- }
-
- Menu {
- id: colorTextFieldContextMenu
- x: colorTextFieldMouseArea.mouseX
- y: colorTextFieldMouseArea.mouseY
- MenuItem {
- text: qsTr("Copy color")
- onTriggered: {
- colorTextField.selectAll();
- colorTextField.copy();
- colorTextField.deselect();
- }
- }
- MenuSeparator {}
- MenuItem {
- text: qsTr("Paste")
- onTriggered: {
- colorTextField.selectAll();
- colorTextField.paste();
- }
- enabled: colorTextField.canPaste
- }
- }
- }
- }
- ListModel {
- id: sliderBoxElements
- ListElement { labelText: "Red value"; colorChannel: 0 }
- ListElement { labelText: "Green value"; colorChannel: 1 }
- ListElement { labelText: "Blue value"; colorChannel: 2 }
- ListElement { labelText: "Alpha value"; colorChannel: 3 }
- }
- ColumnLayout {
- id: sliderBox
- Layout.columnSpan: 3
- Layout.rowSpan: 2
- Layout.fillWidth: true
- Layout.fillHeight: true
-
- Repeater {
- model: sliderBoxElements
- delegate: ColumnLayout {
- Label {
- text: labelText
- }
- Slider {
- id: colorSlider
- property int channel: colorChannel
- from: 0
- to: 255
- stepSize: 1
- value: {
- if (colorSlider.channel == 0)
- return colorDialog.color.r * 255;
- else if (colorSlider.channel == 1)
- return colorDialog.color.g * 255;
- else if (colorSlider.channel == 2)
- return colorDialog.color.b * 255;
- else if (colorSlider.channel == 3)
- return colorDialog.color.a * 255;
- }
-
- Connections {
- function onMoved() {
- var redChannelValue = colorDialog.color.r;
- var greenChannelValue = colorDialog.color.g;
- var blueChannelValue = colorDialog.color.b;
- var alphaChannelValue = colorDialog.color.a;
-
- if (colorSlider.channel == 0)
- redChannelValue = colorSlider.value / 255;
- else if (colorSlider.channel == 1)
- greenChannelValue = colorSlider.value / 255;
- else if (colorSlider.channel == 2)
- blueChannelValue = colorSlider.value / 255;
- else if (colorSlider.channel == 3)
- alphaChannelValue = colorSlider.value / 255;
-
- colorDialog.color = Qt.rgba(redChannelValue, greenChannelValue, blueChannelValue, alphaChannelValue);
- }
- }
- }
- }
- }
- }
- DialogButtonBox {
- id: dialogButtonBox
- Layout.columnSpan: 7
- Layout.alignment: Qt.AlignRight
- Button {
- text: qsTr("Apply")
- onClicked: accept()
- }
- Button {
- text: qsTr("Cancel")
- onClicked: reject()
- }
- }
- }
+ onAccepted : selectedColor(selectedColor)
}
diff --git a/src/webenginequick/ui/ConfirmDialog.qml b/src/webenginequick/ui/ConfirmDialog.qml
index 7b5f1f5cf..cfffe7c4d 100644
--- a/src/webenginequick/ui/ConfirmDialog.qml
+++ b/src/webenginequick/ui/ConfirmDialog.qml
@@ -55,6 +55,7 @@ Dialog {
id: message
Layout.fillWidth: true
color: palette.windowText
+ textFormat: Text.PlainText
}
}
Item {
diff --git a/src/webenginequick/ui/PromptDialog.qml b/src/webenginequick/ui/PromptDialog.qml
index f3a15d48d..275deace8 100644
--- a/src/webenginequick/ui/PromptDialog.qml
+++ b/src/webenginequick/ui/PromptDialog.qml
@@ -52,6 +52,7 @@ Dialog {
id: message
Layout.fillWidth: true
color: palette.windowText
+ textFormat: Text.PlainText
}
TextField {
id:field
diff --git a/src/webenginequick/ui/custom/ColorDialog.qml b/src/webenginequick/ui/custom/ColorDialog.qml
new file mode 100644
index 000000000..895c90198
--- /dev/null
+++ b/src/webenginequick/ui/custom/ColorDialog.qml
@@ -0,0 +1,285 @@
+// Copyright (C) 2021 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+
+import QtQuick
+import QtQuick.Controls
+import QtQuick.Layouts
+
+Dialog {
+ id: colorDialog
+ title: qsTr("Color Picker Dialog")
+ modal: false
+ anchors.centerIn: parent
+ objectName: "colorDialog"
+
+ property bool handled: false
+ property color color
+
+ signal selectedColor(var color)
+ signal rejected()
+
+ function accept() {
+ handled = true;
+ selectedColor(colorDialog.color)
+ close();
+ }
+
+ function reject() {
+ handled = true;
+ rejected();
+ close();
+ }
+
+ // Handle the case where users simply closes or clicks out of the dialog.
+ onVisibleChanged: {
+ if (!visible && !handled) {
+ handled = true;
+ rejected();
+ } else {
+ handled = false;
+ }
+ }
+
+ function selectColorFromPalette(paletteColor) {
+ colorDialog.color = paletteColor;
+ }
+
+ function zeroPadding(text, length = 2) {
+ var textLength = text.length;
+
+ if (textLength >= length) {
+ return text;
+ }
+
+ for (var i = 0; i < length - textLength; i++) {
+ text = "0" + text;
+ }
+
+ return text;
+ }
+
+ function calculateRGBA() {
+
+ var rgbArray = [colorDialog.color.r, colorDialog.color.g, colorDialog.color.b]
+ if (colorDialog.color.a != 1) {
+ rgbArray.push(colorDialog.color.a);
+ }
+
+ for (var i = 0; i < rgbArray.length; i++) {
+ rgbArray[i] = Number(Math.round(rgbArray[i] * 255)).toString(16);
+ rgbArray[i] = zeroPadding(rgbArray[i]);
+ }
+
+ return "#" + rgbArray.join("");
+ }
+
+
+ function isNaNOrUndefined(value) {
+ return value == null || value == undefined || Number.isNaN(value);
+ }
+
+ function parseColorText(colorText) {
+ if (colorText[0] == '#') {
+ colorText = colorText.substring(1);
+ }
+
+ if (!(colorText.length == 6 || colorText.length == 8)) {
+ return undefined;
+ }
+
+ var rgbaValues = [parseInt("0x" + colorText.substring(0,2)),
+ parseInt("0x" + colorText.substring(2,4)),
+ parseInt("0x" + colorText.substring(4,6)),
+ parseInt("0x" + (colorText.length > 6 ? colorText.substring(6,8) : "FF"))]
+
+ for (var i = 0; i < rgbaValues.length; i++) {
+ if (isNaNOrUndefined(rgbaValues[i])) {
+ return undefined;
+ }
+ rgbaValues[i] = rgbaValues[i] / 255;
+ }
+
+ return Qt.rgba(rgbaValues[0], rgbaValues[1], rgbaValues[2], rgbaValues[3]);
+ }
+
+ ListModel {
+ id: colorList
+ ListElement { rectangleColor: "red" }
+ ListElement { rectangleColor: "orangered" }
+ ListElement { rectangleColor: "orange" }
+ ListElement { rectangleColor: "gold" }
+ ListElement { rectangleColor: "yellow" }
+ ListElement { rectangleColor: "yellowgreen" }
+ ListElement { rectangleColor: "green" }
+ ListElement { rectangleColor: "lightskyblue" }
+ ListElement { rectangleColor: "blue" }
+ ListElement { rectangleColor: "blueviolet" }
+ ListElement { rectangleColor: "violet" }
+ ListElement { rectangleColor: "mediumvioletred" }
+ ListElement { rectangleColor: "black" }
+ ListElement { rectangleColor: "white" }
+ }
+
+ contentItem: GridLayout {
+ id: grid
+ columns: 7
+ rows: 5
+
+ Repeater {
+ model: colorList
+ delegate: Rectangle {
+ width: 50
+ height: 50
+ color: rectangleColor
+ border.color: "black"
+ border.width: 1
+
+ MouseArea {
+ anchors.fill: parent
+ onClicked: selectColorFromPalette(parent.color)
+ }
+ }
+ }
+ ColumnLayout {
+ id: colorTools
+ Layout.columnSpan: 4
+ Layout.rowSpan: 2
+ Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
+
+ Rectangle {
+ height: 100
+ width: 200
+ border.color: "black"
+ border.width: 1
+
+ Binding on color {
+ when: colorDialog.color
+ value: colorDialog.color
+ }
+ }
+ TextField {
+ id: colorTextField
+ width: 100
+ selectByMouse: true
+ Layout.alignment: Qt.AlignHCenter
+
+ Binding on text {
+ when: colorDialog.color
+ value: calculateRGBA()
+ delayed: true
+ }
+
+ onTextEdited: {
+ var parsedColor = parseColorText(colorTextField.text);
+ if (parsedColor != undefined) {
+ colorDialog.color = parsedColor;
+ }
+ }
+
+ MouseArea {
+ id: colorTextFieldMouseArea
+ anchors.fill: parent
+ acceptedButtons: Qt.RightButton
+ onClicked: colorTextFieldContextMenu.open()
+ }
+
+ Menu {
+ id: colorTextFieldContextMenu
+ x: colorTextFieldMouseArea.mouseX
+ y: colorTextFieldMouseArea.mouseY
+ MenuItem {
+ text: qsTr("Copy color")
+ onTriggered: {
+ colorTextField.selectAll();
+ colorTextField.copy();
+ colorTextField.deselect();
+ }
+ }
+ MenuSeparator {}
+ MenuItem {
+ text: qsTr("Paste")
+ onTriggered: {
+ colorTextField.selectAll();
+ colorTextField.paste();
+ }
+ enabled: colorTextField.canPaste
+ }
+ }
+ }
+ }
+ ListModel {
+ id: sliderBoxElements
+ ListElement { labelText: "Red value"; colorChannel: 0 }
+ ListElement { labelText: "Green value"; colorChannel: 1 }
+ ListElement { labelText: "Blue value"; colorChannel: 2 }
+ ListElement { labelText: "Alpha value"; colorChannel: 3 }
+ }
+ ColumnLayout {
+ id: sliderBox
+ Layout.columnSpan: 3
+ Layout.rowSpan: 2
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+
+ Repeater {
+ model: sliderBoxElements
+ delegate: ColumnLayout {
+ Label {
+ text: labelText
+ }
+ Slider {
+ id: colorSlider
+ property int channel: colorChannel
+ from: 0
+ to: 255
+ stepSize: 1
+ value: {
+ if (colorSlider.channel == 0)
+ return colorDialog.color.r * 255;
+ else if (colorSlider.channel == 1)
+ return colorDialog.color.g * 255;
+ else if (colorSlider.channel == 2)
+ return colorDialog.color.b * 255;
+ else if (colorSlider.channel == 3)
+ return colorDialog.color.a * 255;
+ }
+
+ Connections {
+ function onMoved() {
+ var redChannelValue = colorDialog.color.r;
+ var greenChannelValue = colorDialog.color.g;
+ var blueChannelValue = colorDialog.color.b;
+ var alphaChannelValue = colorDialog.color.a;
+
+ if (colorSlider.channel == 0)
+ redChannelValue = colorSlider.value / 255;
+ else if (colorSlider.channel == 1)
+ greenChannelValue = colorSlider.value / 255;
+ else if (colorSlider.channel == 2)
+ blueChannelValue = colorSlider.value / 255;
+ else if (colorSlider.channel == 3)
+ alphaChannelValue = colorSlider.value / 255;
+
+ colorDialog.color = Qt.rgba(redChannelValue, greenChannelValue, blueChannelValue, alphaChannelValue);
+ }
+ }
+ }
+ }
+ }
+ }
+ DialogButtonBox {
+ id: dialogButtonBox
+ Layout.columnSpan: 7
+ Layout.alignment: Qt.AlignRight
+
+ Button {
+ text: qsTr("Apply")
+ onClicked: accept()
+ }
+ Button {
+ text: qsTr("Cancel")
+ onClicked: reject()
+ }
+ }
+ }
+}
diff --git a/src/webenginequick/ui_delegates_manager.cpp b/src/webenginequick/ui_delegates_manager.cpp
index b4036c5ee..a4a22fedd 100644
--- a/src/webenginequick/ui_delegates_manager.cpp
+++ b/src/webenginequick/ui_delegates_manager.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "ui_delegates_manager.h"
+#include "ui_delegates_manager_p.h"
#include "api/qquickwebengineaction_p.h"
#include "api/qquickwebengineview_p_p.h"
@@ -14,6 +14,7 @@
#include <touch_selection_menu_controller.h>
#include <web_contents_adapter_client.h>
+#include <QtCore/qdiriterator.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qlist.h>
#include <QtCore/qtimer.h>
@@ -731,8 +732,14 @@ bool UIDelegatesManager::initializeImportDirs(QStringList &dirs, QQmlEngine *eng
}
QFileInfo fi(controlsImportPath);
- if (fi.exists())
+ if (fi.exists()) {
dirs << fi.absolutePath();
+
+ // add subdirectories
+ QDirIterator it(controlsImportPath, QDir::AllDirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
+ while (it.hasNext())
+ dirs << QFileInfo(it.next()).absoluteFilePath();
+ }
}
return !dirs.isEmpty();
}
diff --git a/src/webenginequick/ui_delegates_manager.h b/src/webenginequick/ui_delegates_manager_p.h
index 24dde656c..3502757d7 100644
--- a/src/webenginequick/ui_delegates_manager.h
+++ b/src/webenginequick/ui_delegates_manager_p.h
@@ -4,6 +4,17 @@
#ifndef UI_DELEGATES_MANAGER_H
#define UI_DELEGATES_MANAGER_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/qcoreapplication.h> // Q_DECLARE_TR_FUNCTIONS
#include <QtCore/qobject.h>
#include <QtCore/qpoint.h>
diff --git a/src/webenginewidgets/CMakeLists.txt b/src/webenginewidgets/CMakeLists.txt
index f9365adc9..ff043b45a 100644
--- a/src/webenginewidgets/CMakeLists.txt
+++ b/src/webenginewidgets/CMakeLists.txt
@@ -32,11 +32,12 @@ qt_internal_add_module(WebEngineWidgets
Qt::Gui
Qt::Widgets
Qt::WebEngineCore
+ NO_GENERATE_CPP_EXPORTS
)
qt_internal_extend_target(WebEngineWidgets CONDITION QT_FEATURE_accessibility
SOURCES
- qwebengine_accessible.cpp qwebengine_accessible.h
+ qwebengine_accessible.cpp qwebengine_accessible_p.h
)
qt_internal_extend_target(WebEngineWidgets CONDITION QT_FEATURE_webengine_printing_and_pdf
diff --git a/src/webenginewidgets/api/qwebengineview.cpp b/src/webenginewidgets/api/qwebengineview.cpp
index fd74268f2..5b47d67bf 100644
--- a/src/webenginewidgets/api/qwebengineview.cpp
+++ b/src/webenginewidgets/api/qwebengineview.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2021 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
+#include "qapplication.h"
#include "qwebenginenotificationpresenter_p.h"
#include "qwebengineview.h"
#include "qwebengineview_p.h"
@@ -31,7 +32,7 @@
#include <QQuickWidget>
#if QT_CONFIG(accessibility)
-#include "qwebengine_accessible.h"
+#include "qwebengine_accessible_p.h"
#endif
#if QT_CONFIG(action)
@@ -68,6 +69,14 @@
#include <QThread>
#endif
+QT_BEGIN_NAMESPACE
+class QSpontaneKeyEvent
+{
+public:
+ static inline void makeSpontaneous(QEvent *ev) { ev->setSpontaneous(); }
+};
+QT_END_NAMESPACE
+
namespace QtWebEngineCore {
class WebEngineQuickWidget : public QQuickWidget, public WidgetDelegate
{
@@ -148,6 +157,7 @@ public:
}
void SetClearColor(const QColor &color) override
{
+ setUpdatesEnabled(false);
QQuickWidget::setClearColor(color);
// QQuickWidget is usually blended by punching holes into widgets
// above it to simulate the visual stacking order. If we want it to be
@@ -156,7 +166,8 @@ public:
bool isTranslucent = color.alpha() < 255;
setAttribute(Qt::WA_AlwaysStackOnTop, isTranslucent);
setAttribute(Qt::WA_OpaquePaintEvent, !isTranslucent);
- update();
+ setUpdatesEnabled(true);
+ window()->update();
}
void MoveWindow(const QPoint &screenPos) override
{
@@ -172,6 +183,14 @@ public:
return root->windowHandle();
return nullptr;
}
+ void unhandledWheelEvent(QWheelEvent *ev) override
+ {
+ auto parentWidget = QQuickWidget::parentWidget();
+ if (parentWidget) {
+ QSpontaneKeyEvent::makeSpontaneous(ev);
+ qApp->notify(parentWidget, ev);
+ }
+ }
protected:
void closeEvent(QCloseEvent *event) override
@@ -425,6 +444,8 @@ void QWebEngineViewPrivate::widgetChanged(QtWebEngineCore::WebEngineQuickWidget
#endif
q->layout()->addWidget(newWidget);
q->setFocusProxy(newWidget);
+ if (oldWidget && oldWidget == QApplication::focusWidget())
+ newWidget->setFocus();
newWidget->show();
}
}
@@ -537,8 +558,10 @@ bool QWebEngineViewPrivate::showAuthorizationDialog(const QString &title, const
{
#if QT_CONFIG(messagebox)
Q_Q(QWebEngineView);
- return QMessageBox::question(q, title, message, QMessageBox::Yes, QMessageBox::No)
- == QMessageBox::Yes;
+ QMessageBox msgBox(QMessageBox::Question, title, message, QMessageBox::Yes | QMessageBox::No,
+ q, Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+ msgBox.setTextFormat(Qt::PlainText);
+ return msgBox.exec() == QMessageBox::Yes;
#else
return false;
#endif // QT_CONFIG(messagebox)
@@ -548,8 +571,12 @@ void QWebEngineViewPrivate::javaScriptAlert(const QUrl &url, const QString &msg)
{
#if QT_CONFIG(messagebox)
Q_Q(QWebEngineView);
- QMessageBox::information(q, QStringLiteral("Javascript Alert - %1").arg(url.toString()),
- msg.toHtmlEscaped());
+ QMessageBox msgBox(QMessageBox::Information,
+ QStringLiteral("Javascript Alert - %1").arg(url.toString()),
+ msg, QMessageBox::Ok, q,
+ Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+ msgBox.setTextFormat(Qt::PlainText);
+ msgBox.exec();
#else
Q_UNUSED(msg);
#endif // QT_CONFIG(messagebox)
@@ -559,10 +586,12 @@ bool QWebEngineViewPrivate::javaScriptConfirm(const QUrl &url, const QString &ms
{
#if QT_CONFIG(messagebox)
Q_Q(QWebEngineView);
- return (QMessageBox::information(q,
- QStringLiteral("Javascript Confirm - %1").arg(url.toString()),
- msg.toHtmlEscaped(), QMessageBox::Ok, QMessageBox::Cancel)
- == QMessageBox::Ok);
+ QMessageBox msgBox(QMessageBox::Information,
+ QStringLiteral("Javascript Confirm - %1").arg(url.toString()),
+ msg, QMessageBox::Ok | QMessageBox::Cancel, q,
+ Qt::Dialog | Qt::MSWindowsFixedSizeDialogHint);
+ msgBox.setTextFormat(Qt::PlainText);
+ return msgBox.exec() == QMessageBox::Ok;
#else
Q_UNUSED(msg);
return false;
@@ -575,10 +604,16 @@ bool QWebEngineViewPrivate::javaScriptPrompt(const QUrl &url, const QString &msg
#if QT_CONFIG(inputdialog)
Q_Q(QWebEngineView);
bool ret = false;
+
+ // Workaround: Do not interpret text as Qt::RichText
+ // QInputDialog uses Qt::AutoText that interprets the text string as
+ // Qt::RichText if Qt::mightBeRichText() returns true, otherwise as Qt::PlainText.
+ const QString message = Qt::mightBeRichText(msg) ? msg.toHtmlEscaped() : msg;
+
if (result)
*result = QInputDialog::getText(
q, QStringLiteral("Javascript Prompt - %1").arg(url.toString()),
- msg.toHtmlEscaped(), QLineEdit::Normal, defaultValue.toHtmlEscaped(), &ret);
+ message, QLineEdit::Normal, defaultValue, &ret);
return ret;
#else
Q_UNUSED(msg);
@@ -731,9 +766,9 @@ void QWebEngineViewPrivate::bindPageAndWidget(QWebEnginePagePrivate *pagePrivate
}
}
-QIcon QWebEngineViewPrivate::webActionIcon(QWebEnginePage::WebAction action)
+QIcon QWebEngineViewPrivate::webActionIcon(QWebEnginePage::WebAction action) const
{
- Q_Q(QWebEngineView);
+ Q_Q(const QWebEngineView);
QIcon icon;
QStyle *style = q->style();
@@ -1105,7 +1140,16 @@ QString QWebEngineView::selectedText() const
#if QT_CONFIG(action)
QAction* QWebEngineView::pageAction(QWebEnginePage::WebAction action) const
{
- return page()->action(action);
+ Q_D(const QWebEngineView);
+ QAction *pageAction = page()->action(action);
+
+ if (pageAction->icon().isNull()) {
+ auto icon = d->webActionIcon(action);
+ if (!icon.isNull())
+ pageAction->setIcon(icon);
+ }
+
+ return pageAction;
}
#endif
@@ -1379,7 +1423,8 @@ void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &re
\fn void QWebEngineView::printRequested()
\since 6.2
- This signal is emitted when the JavaScript \c{window.print()} method is called.
+ This signal is emitted when the JavaScript \c{window.print()} method is called or the user pressed the print
+ button of PDF viewer plugin.
Typically, the signal handler can simply call print().
\sa print()
@@ -1408,6 +1453,9 @@ void QWebEngineView::printToPdf(const std::function<void(const QByteArray&)> &re
\note Printing runs on the browser process, which is by default not sandboxed.
+ \note The data generation step of printing can be interrupted for a short period of time using
+ the \l QWebEnginePage::Stop web action.
+
\note This function rasterizes the result when rendering onto \a printer. Please consider raising
the default resolution of \a printer to at least 300 DPI or using printToPdf() to produce
PDF file output more effectively.
@@ -1459,79 +1507,79 @@ void QContextMenuBuilder::addMenuItem(ContextMenuItem menuItem)
switch (menuItem) {
case ContextMenuItem::Back:
- action = thisRef->action(QWebEnginePage::Back);
+ action = m_view->pageAction(QWebEnginePage::Back);
break;
case ContextMenuItem::Forward:
- action = thisRef->action(QWebEnginePage::Forward);
+ action = m_view->pageAction(QWebEnginePage::Forward);
break;
case ContextMenuItem::Reload:
- action = thisRef->action(QWebEnginePage::Reload);
+ action = m_view->pageAction(QWebEnginePage::Reload);
break;
case ContextMenuItem::Cut:
- action = thisRef->action(QWebEnginePage::Cut);
+ action = m_view->pageAction(QWebEnginePage::Cut);
break;
case ContextMenuItem::Copy:
- action = thisRef->action(QWebEnginePage::Copy);
+ action = m_view->pageAction(QWebEnginePage::Copy);
break;
case ContextMenuItem::Paste:
- action = thisRef->action(QWebEnginePage::Paste);
+ action = m_view->pageAction(QWebEnginePage::Paste);
break;
case ContextMenuItem::Undo:
- action = thisRef->action(QWebEnginePage::Undo);
+ action = m_view->pageAction(QWebEnginePage::Undo);
break;
case ContextMenuItem::Redo:
- action = thisRef->action(QWebEnginePage::Redo);
+ action = m_view->pageAction(QWebEnginePage::Redo);
break;
case ContextMenuItem::SelectAll:
- action = thisRef->action(QWebEnginePage::SelectAll);
+ action = m_view->pageAction(QWebEnginePage::SelectAll);
break;
case ContextMenuItem::PasteAndMatchStyle:
- action = thisRef->action(QWebEnginePage::PasteAndMatchStyle);
+ action = m_view->pageAction(QWebEnginePage::PasteAndMatchStyle);
break;
case ContextMenuItem::OpenLinkInNewWindow:
- action = thisRef->action(QWebEnginePage::OpenLinkInNewWindow);
+ action = m_view->pageAction(QWebEnginePage::OpenLinkInNewWindow);
break;
case ContextMenuItem::OpenLinkInNewTab:
- action = thisRef->action(QWebEnginePage::OpenLinkInNewTab);
+ action = m_view->pageAction(QWebEnginePage::OpenLinkInNewTab);
break;
case ContextMenuItem::CopyLinkToClipboard:
- action = thisRef->action(QWebEnginePage::CopyLinkToClipboard);
+ action = m_view->pageAction(QWebEnginePage::CopyLinkToClipboard);
break;
case ContextMenuItem::DownloadLinkToDisk:
- action = thisRef->action(QWebEnginePage::DownloadLinkToDisk);
+ action = m_view->pageAction(QWebEnginePage::DownloadLinkToDisk);
break;
case ContextMenuItem::CopyImageToClipboard:
- action = thisRef->action(QWebEnginePage::CopyImageToClipboard);
+ action = m_view->pageAction(QWebEnginePage::CopyImageToClipboard);
break;
case ContextMenuItem::CopyImageUrlToClipboard:
- action = thisRef->action(QWebEnginePage::CopyImageUrlToClipboard);
+ action = m_view->pageAction(QWebEnginePage::CopyImageUrlToClipboard);
break;
case ContextMenuItem::DownloadImageToDisk:
- action = thisRef->action(QWebEnginePage::DownloadImageToDisk);
+ action = m_view->pageAction(QWebEnginePage::DownloadImageToDisk);
break;
case ContextMenuItem::CopyMediaUrlToClipboard:
- action = thisRef->action(QWebEnginePage::CopyMediaUrlToClipboard);
+ action = m_view->pageAction(QWebEnginePage::CopyMediaUrlToClipboard);
break;
case ContextMenuItem::ToggleMediaControls:
- action = thisRef->action(QWebEnginePage::ToggleMediaControls);
+ action = m_view->pageAction(QWebEnginePage::ToggleMediaControls);
break;
case ContextMenuItem::ToggleMediaLoop:
- action = thisRef->action(QWebEnginePage::ToggleMediaLoop);
+ action = m_view->pageAction(QWebEnginePage::ToggleMediaLoop);
break;
case ContextMenuItem::DownloadMediaToDisk:
- action = thisRef->action(QWebEnginePage::DownloadMediaToDisk);
+ action = m_view->pageAction(QWebEnginePage::DownloadMediaToDisk);
break;
case ContextMenuItem::InspectElement:
- action = thisRef->action(QWebEnginePage::InspectElement);
+ action = m_view->pageAction(QWebEnginePage::InspectElement);
break;
case ContextMenuItem::ExitFullScreen:
- action = thisRef->action(QWebEnginePage::ExitFullScreen);
+ action = m_view->pageAction(QWebEnginePage::ExitFullScreen);
break;
case ContextMenuItem::SavePage:
- action = thisRef->action(QWebEnginePage::SavePage);
+ action = m_view->pageAction(QWebEnginePage::SavePage);
break;
case ContextMenuItem::ViewSource:
- action = thisRef->action(QWebEnginePage::ViewSource);
+ action = m_view->pageAction(QWebEnginePage::ViewSource);
break;
case ContextMenuItem::SpellingSuggestions:
for (int i = 0; i < m_contextData->spellCheckerSuggestions().size() && i < 4; i++) {
diff --git a/src/webenginewidgets/api/qwebengineview_p.h b/src/webenginewidgets/api/qwebengineview_p.h
index 7c0f3fe60..aa330ac23 100644
--- a/src/webenginewidgets/api/qwebengineview_p.h
+++ b/src/webenginewidgets/api/qwebengineview_p.h
@@ -19,6 +19,8 @@
#include "render_view_context_menu_qt.h"
+#include <QtCore/qpointer.h>
+
namespace QtWebEngineCore {
class AutofillPopupController;
class QWebEngineContextMenuRequest;
@@ -85,7 +87,7 @@ public:
static void bindPageAndView(QWebEnginePage *page, QWebEngineView *view);
static void bindPageAndWidget(QWebEnginePagePrivate *pagePrivate,
QtWebEngineCore::WebEngineQuickWidget *widget);
- QIcon webActionIcon(QWebEnginePage::WebAction action);
+ QIcon webActionIcon(QWebEnginePage::WebAction action) const;
void unhandledKeyEvent(QKeyEvent *event) override;
void focusContainer() override;
bool passOnFocus(bool reverse) override;
diff --git a/src/webenginewidgets/doc/snippets/qtwebengine_qwebengineview_snippet.cpp b/src/webenginewidgets/doc/snippets/qtwebengine_qwebengineview_snippet.cpp
index c12490ec1..64531cf3a 100644
--- a/src/webenginewidgets/doc/snippets/qtwebengine_qwebengineview_snippet.cpp
+++ b/src/webenginewidgets/doc/snippets/qtwebengine_qwebengineview_snippet.cpp
@@ -1,5 +1,5 @@
// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
void wrapInFunction()
{
diff --git a/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc b/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc
index 4ab54a2ba..f11f550ff 100644
--- a/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc
+++ b/src/webenginewidgets/doc/snippets/qtwebenginewidgets_build_snippet.qdoc
@@ -7,5 +7,5 @@ QT += webenginewidgets
//! [2]
find_package(Qt6 REQUIRED COMPONENTS WebEngineWidgets)
-target_link_libraries(target PRIVATE Qt::WebEngineWidgets)
+target_link_libraries(target PRIVATE Qt6::WebEngineWidgets)
//! [2]
diff --git a/src/webenginewidgets/doc/snippets/simple/main.cpp b/src/webenginewidgets/doc/snippets/simple/main.cpp
index f887aabaa..08613906b 100644
--- a/src/webenginewidgets/doc/snippets/simple/main.cpp
+++ b/src/webenginewidgets/doc/snippets/simple/main.cpp
@@ -1,18 +1,19 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+//! [Minimal Example]
#include <QApplication>
-#include <QUrl>
#include <QWebEngineView>
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
- QWidget *parent = nullptr;
//! [Using QWebEngineView]
- QWebEngineView *view = new QWebEngineView(parent);
- view->load(QUrl("http://qt-project.org/"));
- view->show();
+ QWebEngineView view;
+ view.load(QUrl("https://qt-project.org/"));
+ view.resize(1024, 750);
+ view.show();
//! [Using QWebEngineView]
return app.exec();
}
+//! [Minimal Example]
diff --git a/src/webenginewidgets/doc/src/qtwebenginewidgets-examples.qdoc b/src/webenginewidgets/doc/src/qtwebenginewidgets-examples.qdoc
index 15f6d08f4..c9bd76bf4 100644
--- a/src/webenginewidgets/doc/src/qtwebenginewidgets-examples.qdoc
+++ b/src/webenginewidgets/doc/src/qtwebenginewidgets-examples.qdoc
@@ -5,7 +5,6 @@
\group webengine-widgetexamples
\title Qt WebEngine Widgets Examples
\brief Examples demonstrating the \QWE Widgets usage.
- \ingroup all-examples
Qt provides an integrated Web browser component based on Chromium, the popular
open source browser engine.
diff --git a/src/webenginewidgets/doc/src/qtwebenginewidgets-module.qdoc b/src/webenginewidgets/doc/src/qtwebenginewidgets-module.qdoc
index df06909df..ef5a1c4b5 100644
--- a/src/webenginewidgets/doc/src/qtwebenginewidgets-module.qdoc
+++ b/src/webenginewidgets/doc/src/qtwebenginewidgets-module.qdoc
@@ -24,4 +24,9 @@
\snippet qtwebenginewidgets_build_snippet.qdoc 2
\endif
+
+ The minimum amount of code needed to load and display an HTML page requires just
+ implementing the \c QWebEngineView class.
+
+ \snippet simple/main.cpp Minimal Example
*/
diff --git a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
index 14e6c3ed8..3153ec952 100644
--- a/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebengineview_lgpl.qdoc
@@ -61,7 +61,7 @@
new windows, such as pop-up windows, you can subclass QWebEngineView and
reimplement the createWindow() function.
- \sa {WebEngine Widgets Simple Browser Example}, {WebEngine Content Manipulation Example}, {WebEngine Markdown Editor Example}
+ \sa {WebEngine Widgets Simple Browser Example}, {WebEngine Content Manipulation Example}
*/
@@ -108,9 +108,8 @@
\fn void QWebEngineView::setHtml(const QString &html, const QUrl &baseUrl)
Sets the content of the web view to the specified \a html content.
- External objects, such as stylesheets or images referenced in the HTML
- document, are located relative to \a baseUrl. For external objects to
- be loaded, \c baseUrl cannot be empty. For example, if \a html
+ \a baseUrl is optional and used to resolve relative URLs in the document,
+ such as referenced images or stylesheets. For example, if \a html
is retrieved from \c http://www.example.com/documents/overview.html, which
is the base URL, then an image referenced with the relative URL, \c diagram.png,
should be at \c{http://www.example.com/documents/diagram.png}.
@@ -144,7 +143,7 @@
is empty, it is assumed that the content is \c{text/plain,charset=US-ASCII}.
External objects referenced in the content are located relative to \a baseUrl.
- For external objects to be loaded, \c baseUrl cannot be empty.
+ For external objects with relative URLs to be loaded, \c baseUrl cannot be empty.
The data is loaded immediately; external objects are loaded asynchronously.
@@ -210,6 +209,7 @@
/*!
\fn QAction *QWebEngineView::pageAction(QWebEnginePage::WebAction action) const
Returns a pointer to a QAction that encapsulates the specified web action \a action.
+ This function will also set a default styled icon to the QAction if it lacks one.
*/
/*!
diff --git a/src/webenginewidgets/plugins/qwebengineview/qwebengineview_plugin.cpp b/src/webenginewidgets/plugins/qwebengineview/qwebengineview_plugin.cpp
index 2ff1de169..6ba64a178 100644
--- a/src/webenginewidgets/plugins/qwebengineview/qwebengineview_plugin.cpp
+++ b/src/webenginewidgets/plugins/qwebengineview/qwebengineview_plugin.cpp
@@ -79,14 +79,6 @@ void QWebEngineViewPlugin::initialize(QDesignerFormEditorInterface * /*core*/)
QString QWebEngineViewPlugin::domXml() const
{
- const auto graphicsApi = QQuickWindow::graphicsApi();
- if (graphicsApi != QSGRendererInterface::OpenGLRhi
- && graphicsApi != QSGRendererInterface::Software) {
- qWarning("Qt Designer: The QWebEngineView custom widget plugin is disabled because it requires OpenGL/Software RHI (current: %d).",
- int(graphicsApi));
- return {};
- }
-
return QStringLiteral("\
<ui language=\"c++\">\
<widget class=\"QWebEngineView\" name=\"webEngineView\">\
diff --git a/src/webenginewidgets/qwebengine_accessible.cpp b/src/webenginewidgets/qwebengine_accessible.cpp
index 6880a5a3a..cbdd90104 100644
--- a/src/webenginewidgets/qwebengine_accessible.cpp
+++ b/src/webenginewidgets/qwebengine_accessible.cpp
@@ -1,7 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-#include "qwebengine_accessible.h"
+#include "qwebengine_accessible_p.h"
#include "qwebengineview.h"
#include "qwebengineview_p.h"
diff --git a/src/webenginewidgets/qwebengine_accessible.h b/src/webenginewidgets/qwebengine_accessible_p.h
index f47996cf7..99604d90d 100644
--- a/src/webenginewidgets/qwebengine_accessible.h
+++ b/src/webenginewidgets/qwebengine_accessible_p.h
@@ -4,6 +4,17 @@
#ifndef QWEBENGINE_ACCESSIBLE_H
#define QWEBENGINE_ACCESSIBLE_H
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
#include <QtCore/QPointer>
#include <QtWidgets/QAccessibleWidget>