summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.qmake.conf2
-rw-r--r--LICENSE.FDL450
-rw-r--r--LICENSE.LGPLv3174
-rw-r--r--coin/qt-installer-package-config.json16
-rw-r--r--configure.json4
-rw-r--r--configure.pri13
-rw-r--r--examples/examples.pro4
-rw-r--r--examples/pdf/multipage/main.cpp73
-rw-r--r--examples/pdf/multipage/multipage.pro14
-rw-r--r--examples/pdf/multipage/resources/document-open.svg13
-rw-r--r--examples/pdf/multipage/resources/edit-clear.svg15
-rw-r--r--examples/pdf/multipage/resources/edit-copy.svg15
-rw-r--r--examples/pdf/multipage/resources/edit-select-all.svg13
-rw-r--r--examples/pdf/multipage/resources/go-down-search.svg13
-rw-r--r--examples/pdf/multipage/resources/go-next-view-page.svg13
-rw-r--r--examples/pdf/multipage/resources/go-previous-view-page.svg13
-rw-r--r--examples/pdf/multipage/resources/go-up-search.svg8
-rw-r--r--examples/pdf/multipage/resources/rotate-left.svg6
-rw-r--r--examples/pdf/multipage/resources/rotate-right.svg6
-rw-r--r--examples/pdf/multipage/resources/test.pdfbin0 -> 80045 bytes
-rw-r--r--examples/pdf/multipage/resources/zoom-fit-best.svg13
-rw-r--r--examples/pdf/multipage/resources/zoom-fit-width.svg13
-rw-r--r--examples/pdf/multipage/resources/zoom-in.svg13
-rw-r--r--examples/pdf/multipage/resources/zoom-original.svg13
-rw-r--r--examples/pdf/multipage/resources/zoom-out.svg13
-rw-r--r--examples/pdf/multipage/viewer.qml360
-rw-r--r--examples/pdf/multipage/viewer.qrc21
-rw-r--r--examples/pdf/pdf.pro3
-rw-r--r--examples/pdf/pdfviewer/main.cpp72
-rw-r--r--examples/pdf/pdfviewer/pdfviewer.pro14
-rw-r--r--examples/pdf/pdfviewer/resources/document-open.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/edit-clear.svg15
-rw-r--r--examples/pdf/pdfviewer/resources/edit-copy.svg15
-rw-r--r--examples/pdf/pdfviewer/resources/edit-select-all.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/go-down-search.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/go-next-view-page.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/go-previous-view-page.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/go-up-search.svg8
-rw-r--r--examples/pdf/pdfviewer/resources/rotate-left.svg6
-rw-r--r--examples/pdf/pdfviewer/resources/rotate-right.svg6
-rw-r--r--examples/pdf/pdfviewer/resources/test.pdfbin0 -> 80045 bytes
-rw-r--r--examples/pdf/pdfviewer/resources/zoom-fit-best.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/zoom-fit-width.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/zoom-in.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/zoom-original.svg13
-rw-r--r--examples/pdf/pdfviewer/resources/zoom-out.svg13
-rw-r--r--examples/pdf/pdfviewer/viewer.qml335
-rw-r--r--examples/pdf/pdfviewer/viewer.qrc21
-rw-r--r--examples/pdfwidgets/pdfviewer/doc/src/pdfviewer.qdoc108
-rw-r--r--examples/pdfwidgets/pdfviewer/images/busy.pngbin0 -> 172 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/fileopen.pngbin0 -> 1771 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/go-next-24.pngbin0 -> 782 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/go-previous-24.pngbin0 -> 797 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/zoom-in-24.pngbin0 -> 1302 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/zoom-in-32.pngbin0 -> 1873 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/zoom-out-24.pngbin0 -> 1247 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/images/zoom-out-32.pngbin0 -> 1749 bytes
-rw-r--r--examples/pdfwidgets/pdfviewer/main.cpp51
-rw-r--r--examples/pdfwidgets/pdfviewer/mainwindow.cpp162
-rw-r--r--examples/pdfwidgets/pdfviewer/mainwindow.h90
-rw-r--r--examples/pdfwidgets/pdfviewer/mainwindow.ui281
-rw-r--r--examples/pdfwidgets/pdfviewer/pageselector.cpp111
-rw-r--r--examples/pdfwidgets/pdfviewer/pageselector.h72
-rw-r--r--examples/pdfwidgets/pdfviewer/pdfviewer.pro23
-rw-r--r--examples/pdfwidgets/pdfviewer/resources.qrc12
-rw-r--r--examples/pdfwidgets/pdfviewer/zoomselector.cpp97
-rw-r--r--examples/pdfwidgets/pdfviewer/zoomselector.h63
-rw-r--r--examples/pdfwidgets/pdfwidgets.pro2
-rw-r--r--mkspecs/features/functions.prf1
-rw-r--r--mkspecs/features/gn_generator.prf16
m---------src/3rdparty0
-rw-r--r--src/buildtools/config/common.pri37
-rw-r--r--src/buildtools/config/ios.pri66
-rw-r--r--src/buildtools/config/linux.pri22
-rw-r--r--src/buildtools/config/mac_osx.pri2
-rw-r--r--src/buildtools/config/pdf.pri36
-rw-r--r--src/buildtools/config/support.pri26
-rw-r--r--src/buildtools/config/windows.pri9
-rw-r--r--src/buildtools/configure.json39
-rw-r--r--src/core/accessibility_tree_formatter_qt.cpp4
-rw-r--r--src/core/api/core_api.pro4
-rw-r--r--src/core/api/qwebengineurlrequestinfo.cpp14
-rw-r--r--src/core/api/qwebengineurlrequestinfo.h4
-rw-r--r--src/core/authentication_dialog_controller.cpp8
-rw-r--r--src/core/browser_accessibility_qt.cpp50
-rw-r--r--src/core/browser_main_parts_qt.cpp4
-rw-r--r--src/core/certificate_error_controller.h3
-rw-r--r--src/core/chromium_overrides.cpp12
-rw-r--r--src/core/clipboard_qt.cpp69
-rw-r--r--src/core/clipboard_qt.h24
-rw-r--r--src/core/command_line_pref_store_qt.cpp90
-rw-r--r--src/core/command_line_pref_store_qt.h56
-rw-r--r--src/core/compositor/compositor.cpp10
-rw-r--r--src/core/compositor/compositor_resource_tracker.cpp2
-rw-r--r--src/core/configure.json19
-rw-r--r--src/core/content_browser_client_qt.cpp599
-rw-r--r--src/core/content_browser_client_qt.h116
-rw-r--r--src/core/content_client_qt.cpp5
-rw-r--r--src/core/content_client_qt.h1
-rw-r--r--src/core/content_main_delegate_qt.cpp64
-rw-r--r--src/core/content_utility_client_qt.cpp16
-rw-r--r--src/core/content_utility_client_qt.h3
-rw-r--r--src/core/core_chromium.pri38
-rw-r--r--src/core/core_gn_config.pri1
-rw-r--r--src/core/devtools_frontend_qt.cpp2
-rw-r--r--src/core/download_manager_delegate_qt.cpp6
-rw-r--r--src/core/download_manager_delegate_qt.h3
-rw-r--r--src/core/extensions/extension_system_qt.cpp9
-rw-r--r--src/core/extensions/extension_web_contents_observer_qt.cpp36
-rw-r--r--src/core/extensions/extension_web_contents_observer_qt.h3
-rw-r--r--src/core/extensions/extensions_browser_client_qt.cpp219
-rw-r--r--src/core/extensions/extensions_browser_client_qt.h8
-rw-r--r--src/core/file_picker_controller.cpp13
-rw-r--r--src/core/login_delegate_qt.cpp10
-rw-r--r--src/core/login_delegate_qt.h1
-rw-r--r--src/core/media_capture_devices_dispatcher.cpp16
-rw-r--r--src/core/net/client_cert_override.cpp2
-rw-r--r--src/core/net/cookie_monster_delegate_qt.cpp188
-rw-r--r--src/core/net/cookie_monster_delegate_qt.h48
-rw-r--r--src/core/net/custom_url_loader_factory.cpp484
-rw-r--r--src/core/net/custom_url_loader_factory.h (renamed from src/core/net/url_request_context_getter_qt.h)40
-rw-r--r--src/core/net/network_delegate_qt.cpp305
-rw-r--r--src/core/net/network_delegate_qt.h102
-rw-r--r--src/core/net/plugin_response_interceptor_url_loader_throttle.cpp135
-rw-r--r--src/core/net/plugin_response_interceptor_url_loader_throttle.h (renamed from src/core/net/url_request_notification.h)62
-rw-r--r--src/core/net/proxy_config_monitor.cpp124
-rw-r--r--src/core/net/proxy_config_monitor.h103
-rw-r--r--src/core/net/proxy_config_service_qt.cpp32
-rw-r--r--src/core/net/proxy_config_service_qt.h12
-rw-r--r--src/core/net/proxying_restricted_cookie_manager_qt.cpp241
-rw-r--r--src/core/net/proxying_restricted_cookie_manager_qt.h (renamed from src/core/net/restricted_cookie_manager_qt.h)63
-rw-r--r--src/core/net/proxying_url_loader_factory_qt.cpp558
-rw-r--r--src/core/net/proxying_url_loader_factory_qt.h109
-rw-r--r--src/core/net/restricted_cookie_manager_qt.cpp185
-rw-r--r--src/core/net/ssl_host_state_delegate_qt.cpp3
-rw-r--r--src/core/net/ssl_host_state_delegate_qt.h3
-rw-r--r--src/core/net/system_network_context_manager.cpp350
-rw-r--r--src/core/net/system_network_context_manager.h187
-rw-r--r--src/core/net/url_request_custom_job.cpp267
-rw-r--r--src/core/net/url_request_custom_job.h95
-rw-r--r--src/core/net/url_request_custom_job_delegate.cpp22
-rw-r--r--src/core/net/url_request_custom_job_proxy.cpp86
-rw-r--r--src/core/net/url_request_custom_job_proxy.h23
-rw-r--r--src/core/net/url_request_notification.cpp194
-rw-r--r--src/core/net/webui_controller_factory_qt.cpp2
-rw-r--r--src/core/ozone/gl_surface_qt.cpp5
-rw-r--r--src/core/ozone/ozone_platform_qt.cpp5
-rw-r--r--src/core/ozone/platform_window_qt.h15
-rw-r--r--src/core/platform_notification_service_qt.cpp3
-rw-r--r--src/core/pref_service_adapter.cpp12
-rw-r--r--src/core/printing/print_view_manager_base_qt.cpp49
-rw-r--r--src/core/printing/print_view_manager_base_qt.h13
-rw-r--r--src/core/printing/print_view_manager_qt.cpp73
-rw-r--r--src/core/printing/print_view_manager_qt.h11
-rw-r--r--src/core/profile_adapter.cpp100
-rw-r--r--src/core/profile_io_data_qt.cpp567
-rw-r--r--src/core/profile_io_data_qt.h56
-rw-r--r--src/core/profile_qt.cpp51
-rw-r--r--src/core/profile_qt.h10
-rw-r--r--src/core/qtwebengine.gni1
-rw-r--r--src/core/qtwebengine_sources.gni10
-rw-r--r--src/core/quota_permission_context_qt.cpp4
-rw-r--r--src/core/render_widget_host_view_qt.cpp24
-rw-r--r--src/core/render_widget_host_view_qt.h4
-rw-r--r--src/core/renderer/content_renderer_client_qt.cpp191
-rw-r--r--src/core/renderer/content_renderer_client_qt.h61
-rw-r--r--src/core/renderer/content_settings_observer_qt.cpp52
-rw-r--r--src/core/renderer/content_settings_observer_qt.h12
-rw-r--r--src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp103
-rw-r--r--src/core/renderer/plugins/loadable_plugin_placeholder_qt.h (renamed from src/core/net/custom_protocol_handler.h)71
-rw-r--r--src/core/renderer/plugins/plugin_placeholder_qt.cpp (renamed from src/core/net/custom_protocol_handler.cpp)41
-rw-r--r--src/core/renderer/plugins/plugin_placeholder_qt.h (renamed from src/core/net/url_request_context_getter_qt.cpp)53
-rw-r--r--src/core/renderer/print_web_view_helper_delegate_qt.cpp12
-rw-r--r--src/core/renderer/print_web_view_helper_delegate_qt.h9
-rw-r--r--src/core/renderer/render_frame_observer_qt.cpp21
-rw-r--r--src/core/renderer/render_frame_observer_qt.h11
-rw-r--r--src/core/renderer/render_thread_observer_qt.cpp8
-rw-r--r--src/core/renderer/render_thread_observer_qt.h15
-rw-r--r--src/core/renderer/render_view_observer_qt.cpp16
-rw-r--r--src/core/renderer/render_view_observer_qt.h7
-rw-r--r--src/core/renderer/user_resource_controller.cpp47
-rw-r--r--src/core/renderer/user_resource_controller.h3
-rw-r--r--src/core/renderer/web_channel_ipc_transport.cpp47
-rw-r--r--src/core/renderer/web_channel_ipc_transport.h15
-rw-r--r--src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp2
-rw-r--r--src/core/renderer_host/render_view_observer_host_qt.cpp7
-rw-r--r--src/core/renderer_host/render_view_observer_host_qt.h10
-rw-r--r--src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp186
-rw-r--r--src/core/renderer_host/resource_dispatcher_host_delegate_qt.h77
-rw-r--r--src/core/renderer_host/user_resource_controller_host.cpp43
-rw-r--r--src/core/renderer_host/user_resource_controller_host.h3
-rw-r--r--src/core/renderer_host/web_channel_ipc_transport_host.cpp20
-rw-r--r--src/core/renderer_host/web_channel_ipc_transport_host.h6
-rw-r--r--src/core/service/service_qt.cpp169
-rw-r--r--src/core/service/service_qt.h75
-rw-r--r--src/core/type_conversion.cpp20
-rw-r--r--src/core/user_notification_controller.cpp1
-rw-r--r--src/core/web_contents_adapter.cpp32
-rw-r--r--src/core/web_contents_adapter.h1
-rw-r--r--src/core/web_contents_adapter_client.h1
-rw-r--r--src/core/web_contents_delegate_qt.cpp16
-rw-r--r--src/core/web_contents_delegate_qt.h2
-rw-r--r--src/core/web_contents_view_qt.cpp2
-rw-r--r--src/core/web_contents_view_qt.h2
-rw-r--r--src/core/web_engine_context.cpp73
-rw-r--r--src/core/web_engine_context_threads.cpp4
-rw-r--r--src/core/web_engine_settings.cpp20
-rw-r--r--src/core/web_event_factory.cpp8
-rw-r--r--src/pdf/api/qpdfbookmarkmodel.h98
-rw-r--r--src/pdf/api/qpdfdestination.h85
-rw-r--r--src/pdf/api/qpdfdestination_p.h71
-rw-r--r--src/pdf/api/qpdfdocument.h138
-rw-r--r--src/pdf/api/qpdfdocument_p.h113
-rw-r--r--src/pdf/api/qpdfdocumentrenderoptions.h94
-rw-r--r--src/pdf/api/qpdflinkmodel_p.h106
-rw-r--r--src/pdf/api/qpdflinkmodel_p_p.h91
-rw-r--r--src/pdf/api/qpdfnamespace.h73
-rw-r--r--src/pdf/api/qpdfpagenavigation.h92
-rw-r--r--src/pdf/api/qpdfpagerenderer.h92
-rw-r--r--src/pdf/api/qpdfsearchmodel.h98
-rw-r--r--src/pdf/api/qpdfsearchmodel_p.h86
-rw-r--r--src/pdf/api/qpdfsearchresult.h76
-rw-r--r--src/pdf/api/qpdfsearchresult_p.h72
-rw-r--r--src/pdf/api/qpdfselection.h85
-rw-r--r--src/pdf/api/qpdfselection_p.h59
-rw-r--r--src/pdf/api/qtpdfglobal.h59
-rw-r--r--src/pdf/configure.json64
-rw-r--r--src/pdf/doc/qtpdf.qdocconf58
-rw-r--r--src/pdf/doc/snippets/qtpdf-build.cmake2
-rw-r--r--src/pdf/doc/snippets/qtpdf_build_snippet.qdoc35
-rw-r--r--src/pdf/doc/src/qtpdf-examples.qdoc37
-rw-r--r--src/pdf/doc/src/qtpdf-index.qdoc76
-rw-r--r--src/pdf/doc/src/qtpdf-module.qdoc50
-rw-r--r--src/pdf/gn_run.pro70
-rw-r--r--src/pdf/jsbridge.cpp38
-rw-r--r--src/pdf/pdf.pro16
-rw-r--r--src/pdf/pdfcore.pro93
-rw-r--r--src/pdf/pdfcore_generator.pro15
-rw-r--r--src/pdf/qpdfbookmarkmodel.cpp363
-rw-r--r--src/pdf/qpdfdestination.cpp145
-rw-r--r--src/pdf/qpdfdocument.cpp803
-rw-r--r--src/pdf/qpdfdocumentrenderoptions.qdoc139
-rw-r--r--src/pdf/qpdflinkmodel.cpp251
-rw-r--r--src/pdf/qpdfnamespace.qdoc74
-rw-r--r--src/pdf/qpdfpagenavigation.cpp314
-rw-r--r--src/pdf/qpdfpagerenderer.cpp361
-rw-r--r--src/pdf/qpdfsearchmodel.cpp324
-rw-r--r--src/pdf/qpdfsearchresult.cpp80
-rw-r--r--src/pdf/qpdfselection.cpp149
-rw-r--r--src/pdf/qtpdf.gni7
-rw-r--r--src/pdf/quick/plugin.cpp101
-rw-r--r--src/pdf/quick/plugins.qmltypes52
-rw-r--r--src/pdf/quick/qml/+material/PdfStyle.qml54
-rw-r--r--src/pdf/quick/qml/+universal/PdfStyle.qml55
-rw-r--r--src/pdf/quick/qml/PdfMultiPageView.qml379
-rw-r--r--src/pdf/quick/qml/PdfPageView.qml276
-rw-r--r--src/pdf/quick/qml/PdfScrollablePageView.qml290
-rw-r--r--src/pdf/quick/qml/PdfStyle.qml54
-rw-r--r--src/pdf/quick/qmldir4
-rw-r--r--src/pdf/quick/qquickpdfdocument.cpp306
-rw-r--r--src/pdf/quick/qquickpdfdocument_p.h137
-rw-r--r--src/pdf/quick/qquickpdflinkmodel.cpp132
-rw-r--r--src/pdf/quick/qquickpdflinkmodel_p.h87
-rw-r--r--src/pdf/quick/qquickpdfnavigationstack.cpp266
-rw-r--r--src/pdf/quick/qquickpdfnavigationstack_p.h102
-rw-r--r--src/pdf/quick/qquickpdfsearchmodel.cpp277
-rw-r--r--src/pdf/quick/qquickpdfsearchmodel_p.h110
-rw-r--r--src/pdf/quick/qquickpdfselection.cpp284
-rw-r--r--src/pdf/quick/qquickpdfselection_p.h123
-rw-r--r--src/pdf/quick/quick.pro34
-rw-r--r--src/pdf/quick/resources.qrc10
-rw-r--r--src/pdfwidgets/configure.json28
-rw-r--r--src/pdfwidgets/pdfwidgets.pro12
-rw-r--r--src/pdfwidgets/qpdfview.cpp493
-rw-r--r--src/pdfwidgets/qpdfview.h122
-rw-r--r--src/pdfwidgets/qpdfview_p.h119
-rw-r--r--src/pdfwidgets/qtpdfwidgetsglobal.h59
-rw-r--r--src/plugins/imageformats/imageformats.pro2
-rw-r--r--src/plugins/imageformats/pdf/main.cpp74
-rw-r--r--src/plugins/imageformats/pdf/pdf.json4
-rw-r--r--src/plugins/imageformats/pdf/pdf.pro11
-rw-r--r--src/plugins/imageformats/pdf/qpdfiohandler.cpp239
-rw-r--r--src/plugins/imageformats/pdf/qpdfiohandler_p.h88
-rw-r--r--src/plugins/plugins.pro3
-rw-r--r--src/process/QtWebEngineProcess.entitlements (renamed from src/process/Entitlements_mac.plist)0
-rw-r--r--src/process/process.pro17
-rw-r--r--src/src.pro19
-rw-r--r--src/tools/qwebengine_convert_dict/main.cpp32
-rw-r--r--src/webengine/api/qquickwebenginehistory.cpp14
-rw-r--r--src/webengine/api/qquickwebenginehistory_p.h1
-rw-r--r--src/webengine/api/qquickwebenginetestsupport.cpp2
-rw-r--r--src/webengine/api/qquickwebengineview.cpp12
-rw-r--r--src/webengine/api/qquickwebengineview_p.h7
-rw-r--r--src/webengine/api/qquickwebengineview_p_p.h1
-rw-r--r--src/webengine/doc/src/qwebengine-licensing.qdoc2
-rw-r--r--src/webengine/doc/src/webengineview_lgpl.qdoc24
-rw-r--r--src/webengine/plugin/plugin.cpp2
-rw-r--r--src/webengine/plugin/plugins.qmltypes6
-rw-r--r--src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp2
-rw-r--r--src/webenginewidgets/api/qwebenginepage.cpp31
-rw-r--r--src/webenginewidgets/api/qwebenginepage.h3
-rw-r--r--src/webenginewidgets/api/qwebenginepage_p.h1
-rw-r--r--src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc3
-rw-r--r--sync.profile3
-rw-r--r--tests/auto/auto.pro5
-rw-r--r--tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp8
-rw-r--r--tests/auto/pdf/pdf.pro8
-rw-r--r--tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks.pdfbin0 -> 8925 bytes
-rw-r--r--tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks_pages.pdfbin0 -> 27523 bytes
-rw-r--r--tests/auto/pdf/qpdfbookmarkmodel/qpdfbookmarkmodel.pro5
-rw-r--r--tests/auto/pdf/qpdfbookmarkmodel/tst_qpdfbookmarkmodel.cpp287
-rw-r--r--tests/auto/pdf/qpdfdocument/BLACKLIST6
-rw-r--r--tests/auto/pdf/qpdfdocument/pdf-sample.metadata.pdfbin0 -> 9298 bytes
-rw-r--r--tests/auto/pdf/qpdfdocument/pdf-sample.protected.pdfbin0 -> 9138 bytes
-rw-r--r--tests/auto/pdf/qpdfdocument/qpdfdocument.pro6
-rw-r--r--tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp386
-rw-r--r--tests/auto/pdf/qpdfpagenavigation/pdf-sample.pagenavigation.pdfbin0 -> 27523 bytes
-rw-r--r--tests/auto/pdf/qpdfpagenavigation/qpdfpagenavigation.pro5
-rw-r--r--tests/auto/pdf/qpdfpagenavigation/tst_qpdfpagenavigation.cpp200
-rw-r--r--tests/auto/pdf/qpdfpagerenderer/pdf-sample.pagerenderer.pdfbin0 -> 27523 bytes
-rw-r--r--tests/auto/pdf/qpdfpagerenderer/qpdfpagerenderer.pro5
-rw-r--r--tests/auto/pdf/qpdfpagerenderer/tst_qpdfpagerenderer.cpp184
-rw-r--r--tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro5
-rw-r--r--tests/auto/pdf/qpdfsearchmodel/test.pdfbin0 -> 80045 bytes
-rw-r--r--tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp69
-rw-r--r--tests/auto/quick/publicapi/tst_publicapi.cpp3
-rw-r--r--tests/auto/quick/qmltests/data/test4.html200
-rw-r--r--tests/auto/quick/qmltests/data/tst_loadUrl.qml2
-rw-r--r--tests/auto/quick/qmltests/data/tst_navigationHistory.qml7
-rw-r--r--tests/auto/quick/qquickwebengineview/BLACKLIST3
-rw-r--r--tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp10
-rw-r--r--tests/auto/widgets/accessibility/tst_accessibility.cpp320
-rw-r--r--tests/auto/widgets/origins/tst_origins.cpp22
-rw-r--r--tests/auto/widgets/proxypac/proxypac.pri5
-rw-r--r--tests/auto/widgets/proxypac/proxypac.pro13
-rw-r--r--tests/auto/widgets/proxypac/proxypac.qrc7
-rw-r--r--tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro9
-rw-r--r--tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro7
-rw-r--r--tests/auto/widgets/qwebenginepage/BLACKLIST6
-rw-r--r--tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp82
-rw-r--r--tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp47
-rw-r--r--tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp105
-rw-r--r--tests/auto/widgets/schemes/tst_schemes.cpp76
-rw-r--r--tests/auto/widgets/spellchecking/tst_spellchecking.cpp8
-rw-r--r--tests/auto/widgets/util.h2
-rw-r--r--tests/manual/quick/pdf/listview.qml95
-rw-r--r--tests/manual/quick/pdf/pessimizedListView.qml174
-rw-r--r--tests/manual/quick/pdf/simplest.qml66
-rw-r--r--tests/manual/quick/pdf/test.pdfbin0 -> 80045 bytes
-rw-r--r--tests/manual/quick/pdf/withdoc.qml206
-rw-r--r--tools/about_credits_entry.tmpl1
-rw-r--r--tools/scripts/git_submodule.py14
-rwxr-xr-xtools/scripts/take_snapshot.py70
-rw-r--r--tools/scripts/version_resolver.py33
355 files changed, 19675 insertions, 4237 deletions
diff --git a/.gitignore b/.gitignore
index 71d4cbb0e..cd5829835 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,13 +1,13 @@
.qmake.cache
.qmake.stash
src/3rdparty_upstream/patches
+src/3rdparty_upstream/gn
src/3rdparty_upstream/ninja
src/3rdparty_upstream/chromium
src/core/Debug
src/core/Release
src/core/api/Release
src/core/api/Debug
-src/core/gypfiles
examples/webengine/quicknanobrowser/quicknanobrowser
examples/webengine/quicknanobrowser/quicknanobrowser.app
examples/webenginewidgets/browser/browser
diff --git a/.qmake.conf b/.qmake.conf
index adf09de55..a942dacce 100644
--- a/.qmake.conf
+++ b/.qmake.conf
@@ -5,4 +5,4 @@ QTWEBENGINE_OUT_ROOT = $$shadowed($$PWD)
load(qt_build_config)
CONFIG += warning_clean
-MODULE_VERSION = 5.14.2
+MODULE_VERSION = 5.15.0
diff --git a/LICENSE.FDL b/LICENSE.FDL
new file mode 100644
index 000000000..086177c0a
--- /dev/null
+++ b/LICENSE.FDL
@@ -0,0 +1,450 @@
+ GNU Free Documentation License
+ Version 1.3, 3 November 2008
+
+
+ Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
+ <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+0. PREAMBLE
+
+The purpose of this License is to make a manual, textbook, or other
+functional and useful document "free" in the sense of freedom: to
+assure everyone the effective freedom to copy and redistribute it,
+with or without modifying it, either commercially or noncommercially.
+Secondarily, this License preserves for the author and publisher a way
+to get credit for their work, while not being considered responsible
+for modifications made by others.
+
+This License is a kind of "copyleft", which means that derivative
+works of the document must themselves be free in the same sense. It
+complements the GNU General Public License, which is a copyleft
+license designed for free software.
+
+We have designed this License in order to use it for manuals for free
+software, because free software needs free documentation: a free
+program should come with manuals providing the same freedoms that the
+software does. But this License is not limited to software manuals;
+it can be used for any textual work, regardless of subject matter or
+whether it is published as a printed book. We recommend this License
+principally for works whose purpose is instruction or reference.
+
+
+1. APPLICABILITY AND DEFINITIONS
+
+This License applies to any manual or other work, in any medium, that
+contains a notice placed by the copyright holder saying it can be
+distributed under the terms of this License. Such a notice grants a
+world-wide, royalty-free license, unlimited in duration, to use that
+work under the conditions stated herein. The "Document", below,
+refers to any such manual or work. Any member of the public is a
+licensee, and is addressed as "you". You accept the license if you
+copy, modify or distribute the work in a way requiring permission
+under copyright law.
+
+A "Modified Version" of the Document means any work containing the
+Document or a portion of it, either copied verbatim, or with
+modifications and/or translated into another language.
+
+A "Secondary Section" is a named appendix or a front-matter section of
+the Document that deals exclusively with the relationship of the
+publishers or authors of the Document to the Document's overall
+subject (or to related matters) and contains nothing that could fall
+directly within that overall subject. (Thus, if the Document is in
+part a textbook of mathematics, a Secondary Section may not explain
+any mathematics.) The relationship could be a matter of historical
+connection with the subject or with related matters, or of legal,
+commercial, philosophical, ethical or political position regarding
+them.
+
+The "Invariant Sections" are certain Secondary Sections whose titles
+are designated, as being those of Invariant Sections, in the notice
+that says that the Document is released under this License. If a
+section does not fit the above definition of Secondary then it is not
+allowed to be designated as Invariant. The Document may contain zero
+Invariant Sections. If the Document does not identify any Invariant
+Sections then there are none.
+
+The "Cover Texts" are certain short passages of text that are listed,
+as Front-Cover Texts or Back-Cover Texts, in the notice that says that
+the Document is released under this License. A Front-Cover Text may
+be at most 5 words, and a Back-Cover Text may be at most 25 words.
+
+A "Transparent" copy of the Document means a machine-readable copy,
+represented in a format whose specification is available to the
+general public, that is suitable for revising the document
+straightforwardly with generic text editors or (for images composed of
+pixels) generic paint programs or (for drawings) some widely available
+drawing editor, and that is suitable for input to text formatters or
+for automatic translation to a variety of formats suitable for input
+to text formatters. A copy made in an otherwise Transparent file
+format whose markup, or absence of markup, has been arranged to thwart
+or discourage subsequent modification by readers is not Transparent.
+An image format is not Transparent if used for any substantial amount
+of text. A copy that is not "Transparent" is called "Opaque".
+
+Examples of suitable formats for Transparent copies include plain
+ASCII without markup, Texinfo input format, LaTeX input format, SGML
+or XML using a publicly available DTD, and standard-conforming simple
+HTML, PostScript or PDF designed for human modification. Examples of
+transparent image formats include PNG, XCF and JPG. Opaque formats
+include proprietary formats that can be read and edited only by
+proprietary word processors, SGML or XML for which the DTD and/or
+processing tools are not generally available, and the
+machine-generated HTML, PostScript or PDF produced by some word
+processors for output purposes only.
+
+The "Title Page" means, for a printed book, the title page itself,
+plus such following pages as are needed to hold, legibly, the material
+this License requires to appear in the title page. For works in
+formats which do not have any title page as such, "Title Page" means
+the text near the most prominent appearance of the work's title,
+preceding the beginning of the body of the text.
+
+The "publisher" means any person or entity that distributes copies of
+the Document to the public.
+
+A section "Entitled XYZ" means a named subunit of the Document whose
+title either is precisely XYZ or contains XYZ in parentheses following
+text that translates XYZ in another language. (Here XYZ stands for a
+specific section name mentioned below, such as "Acknowledgements",
+"Dedications", "Endorsements", or "History".) To "Preserve the Title"
+of such a section when you modify the Document means that it remains a
+section "Entitled XYZ" according to this definition.
+
+The Document may include Warranty Disclaimers next to the notice which
+states that this License applies to the Document. These Warranty
+Disclaimers are considered to be included by reference in this
+License, but only as regards disclaiming warranties: any other
+implication that these Warranty Disclaimers may have is void and has
+no effect on the meaning of this License.
+
+2. VERBATIM COPYING
+
+You may copy and distribute the Document in any medium, either
+commercially or noncommercially, provided that this License, the
+copyright notices, and the license notice saying this License applies
+to the Document are reproduced in all copies, and that you add no
+other conditions whatsoever to those of this License. You may not use
+technical measures to obstruct or control the reading or further
+copying of the copies you make or distribute. However, you may accept
+compensation in exchange for copies. If you distribute a large enough
+number of copies you must also follow the conditions in section 3.
+
+You may also lend copies, under the same conditions stated above, and
+you may publicly display copies.
+
+
+3. COPYING IN QUANTITY
+
+If you publish printed copies (or copies in media that commonly have
+printed covers) of the Document, numbering more than 100, and the
+Document's license notice requires Cover Texts, you must enclose the
+copies in covers that carry, clearly and legibly, all these Cover
+Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
+the back cover. Both covers must also clearly and legibly identify
+you as the publisher of these copies. The front cover must present
+the full title with all words of the title equally prominent and
+visible. You may add other material on the covers in addition.
+Copying with changes limited to the covers, as long as they preserve
+the title of the Document and satisfy these conditions, can be treated
+as verbatim copying in other respects.
+
+If the required texts for either cover are too voluminous to fit
+legibly, you should put the first ones listed (as many as fit
+reasonably) on the actual cover, and continue the rest onto adjacent
+pages.
+
+If you publish or distribute Opaque copies of the Document numbering
+more than 100, you must either include a machine-readable Transparent
+copy along with each Opaque copy, or state in or with each Opaque copy
+a computer-network location from which the general network-using
+public has access to download using public-standard network protocols
+a complete Transparent copy of the Document, free of added material.
+If you use the latter option, you must take reasonably prudent steps,
+when you begin distribution of Opaque copies in quantity, to ensure
+that this Transparent copy will remain thus accessible at the stated
+location until at least one year after the last time you distribute an
+Opaque copy (directly or through your agents or retailers) of that
+edition to the public.
+
+It is requested, but not required, that you contact the authors of the
+Document well before redistributing any large number of copies, to
+give them a chance to provide you with an updated version of the
+Document.
+
+
+4. MODIFICATIONS
+
+You may copy and distribute a Modified Version of the Document under
+the conditions of sections 2 and 3 above, provided that you release
+the Modified Version under precisely this License, with the Modified
+Version filling the role of the Document, thus licensing distribution
+and modification of the Modified Version to whoever possesses a copy
+of it. In addition, you must do these things in the Modified Version:
+
+A. Use in the Title Page (and on the covers, if any) a title distinct
+ from that of the Document, and from those of previous versions
+ (which should, if there were any, be listed in the History section
+ of the Document). You may use the same title as a previous version
+ if the original publisher of that version gives permission.
+B. List on the Title Page, as authors, one or more persons or entities
+ responsible for authorship of the modifications in the Modified
+ Version, together with at least five of the principal authors of the
+ Document (all of its principal authors, if it has fewer than five),
+ unless they release you from this requirement.
+C. State on the Title page the name of the publisher of the
+ Modified Version, as the publisher.
+D. Preserve all the copyright notices of the Document.
+E. Add an appropriate copyright notice for your modifications
+ adjacent to the other copyright notices.
+F. Include, immediately after the copyright notices, a license notice
+ giving the public permission to use the Modified Version under the
+ terms of this License, in the form shown in the Addendum below.
+G. Preserve in that license notice the full lists of Invariant Sections
+ and required Cover Texts given in the Document's license notice.
+H. Include an unaltered copy of this License.
+I. Preserve the section Entitled "History", Preserve its Title, and add
+ to it an item stating at least the title, year, new authors, and
+ publisher of the Modified Version as given on the Title Page. If
+ there is no section Entitled "History" in the Document, create one
+ stating the title, year, authors, and publisher of the Document as
+ given on its Title Page, then add an item describing the Modified
+ Version as stated in the previous sentence.
+J. Preserve the network location, if any, given in the Document for
+ public access to a Transparent copy of the Document, and likewise
+ the network locations given in the Document for previous versions
+ it was based on. These may be placed in the "History" section.
+ You may omit a network location for a work that was published at
+ least four years before the Document itself, or if the original
+ publisher of the version it refers to gives permission.
+K. For any section Entitled "Acknowledgements" or "Dedications",
+ Preserve the Title of the section, and preserve in the section all
+ the substance and tone of each of the contributor acknowledgements
+ and/or dedications given therein.
+L. Preserve all the Invariant Sections of the Document,
+ unaltered in their text and in their titles. Section numbers
+ or the equivalent are not considered part of the section titles.
+M. Delete any section Entitled "Endorsements". Such a section
+ may not be included in the Modified Version.
+N. Do not retitle any existing section to be Entitled "Endorsements"
+ or to conflict in title with any Invariant Section.
+O. Preserve any Warranty Disclaimers.
+
+If the Modified Version includes new front-matter sections or
+appendices that qualify as Secondary Sections and contain no material
+copied from the Document, you may at your option designate some or all
+of these sections as invariant. To do this, add their titles to the
+list of Invariant Sections in the Modified Version's license notice.
+These titles must be distinct from any other section titles.
+
+You may add a section Entitled "Endorsements", provided it contains
+nothing but endorsements of your Modified Version by various
+parties--for example, statements of peer review or that the text has
+been approved by an organization as the authoritative definition of a
+standard.
+
+You may add a passage of up to five words as a Front-Cover Text, and a
+passage of up to 25 words as a Back-Cover Text, to the end of the list
+of Cover Texts in the Modified Version. Only one passage of
+Front-Cover Text and one of Back-Cover Text may be added by (or
+through arrangements made by) any one entity. If the Document already
+includes a cover text for the same cover, previously added by you or
+by arrangement made by the same entity you are acting on behalf of,
+you may not add another; but you may replace the old one, on explicit
+permission from the previous publisher that added the old one.
+
+The author(s) and publisher(s) of the Document do not by this License
+give permission to use their names for publicity for or to assert or
+imply endorsement of any Modified Version.
+
+
+5. COMBINING DOCUMENTS
+
+You may combine the Document with other documents released under this
+License, under the terms defined in section 4 above for modified
+versions, provided that you include in the combination all of the
+Invariant Sections of all of the original documents, unmodified, and
+list them all as Invariant Sections of your combined work in its
+license notice, and that you preserve all their Warranty Disclaimers.
+
+The combined work need only contain one copy of this License, and
+multiple identical Invariant Sections may be replaced with a single
+copy. If there are multiple Invariant Sections with the same name but
+different contents, make the title of each such section unique by
+adding at the end of it, in parentheses, the name of the original
+author or publisher of that section if known, or else a unique number.
+Make the same adjustment to the section titles in the list of
+Invariant Sections in the license notice of the combined work.
+
+In the combination, you must combine any sections Entitled "History"
+in the various original documents, forming one section Entitled
+"History"; likewise combine any sections Entitled "Acknowledgements",
+and any sections Entitled "Dedications". You must delete all sections
+Entitled "Endorsements".
+
+
+6. COLLECTIONS OF DOCUMENTS
+
+You may make a collection consisting of the Document and other
+documents released under this License, and replace the individual
+copies of this License in the various documents with a single copy
+that is included in the collection, provided that you follow the rules
+of this License for verbatim copying of each of the documents in all
+other respects.
+
+You may extract a single document from such a collection, and
+distribute it individually under this License, provided you insert a
+copy of this License into the extracted document, and follow this
+License in all other respects regarding verbatim copying of that
+document.
+
+
+7. AGGREGATION WITH INDEPENDENT WORKS
+
+A compilation of the Document or its derivatives with other separate
+and independent documents or works, in or on a volume of a storage or
+distribution medium, is called an "aggregate" if the copyright
+resulting from the compilation is not used to limit the legal rights
+of the compilation's users beyond what the individual works permit.
+When the Document is included in an aggregate, this License does not
+apply to the other works in the aggregate which are not themselves
+derivative works of the Document.
+
+If the Cover Text requirement of section 3 is applicable to these
+copies of the Document, then if the Document is less than one half of
+the entire aggregate, the Document's Cover Texts may be placed on
+covers that bracket the Document within the aggregate, or the
+electronic equivalent of covers if the Document is in electronic form.
+Otherwise they must appear on printed covers that bracket the whole
+aggregate.
+
+
+8. TRANSLATION
+
+Translation is considered a kind of modification, so you may
+distribute translations of the Document under the terms of section 4.
+Replacing Invariant Sections with translations requires special
+permission from their copyright holders, but you may include
+translations of some or all Invariant Sections in addition to the
+original versions of these Invariant Sections. You may include a
+translation of this License, and all the license notices in the
+Document, and any Warranty Disclaimers, provided that you also include
+the original English version of this License and the original versions
+of those notices and disclaimers. In case of a disagreement between
+the translation and the original version of this License or a notice
+or disclaimer, the original version will prevail.
+
+If a section in the Document is Entitled "Acknowledgements",
+"Dedications", or "History", the requirement (section 4) to Preserve
+its Title (section 1) will typically require changing the actual
+title.
+
+
+9. TERMINATION
+
+You may not copy, modify, sublicense, or distribute the Document
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense, or distribute it is void, and
+will automatically terminate your rights under this License.
+
+However, if you cease all violation of this License, then your license
+from a particular copyright holder is reinstated (a) provisionally,
+unless and until the copyright holder explicitly and finally
+terminates your license, and (b) permanently, if the copyright holder
+fails to notify you of the violation by some reasonable means prior to
+60 days after the cessation.
+
+Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, receipt of a copy of some or all of the same material does
+not give you any rights to use it.
+
+
+10. FUTURE REVISIONS OF THIS LICENSE
+
+The Free Software Foundation may publish new, revised versions of the
+GNU Free Documentation License from time to time. Such new versions
+will be similar in spirit to the present version, but may differ in
+detail to address new problems or concerns. See
+http://www.gnu.org/copyleft/.
+
+Each version of the License is given a distinguishing version number.
+If the Document specifies that a particular numbered version of this
+License "or any later version" applies to it, you have the option of
+following the terms and conditions either of that specified version or
+of any later version that has been published (not as a draft) by the
+Free Software Foundation. If the Document does not specify a version
+number of this License, you may choose any version ever published (not
+as a draft) by the Free Software Foundation. If the Document
+specifies that a proxy can decide which future versions of this
+License can be used, that proxy's public statement of acceptance of a
+version permanently authorizes you to choose that version for the
+Document.
+
+11. RELICENSING
+
+"Massive Multiauthor Collaboration Site" (or "MMC Site") means any
+World Wide Web server that publishes copyrightable works and also
+provides prominent facilities for anybody to edit those works. A
+public wiki that anybody can edit is an example of such a server. A
+"Massive Multiauthor Collaboration" (or "MMC") contained in the site
+means any set of copyrightable works thus published on the MMC site.
+
+"CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
+license published by Creative Commons Corporation, a not-for-profit
+corporation with a principal place of business in San Francisco,
+California, as well as future copyleft versions of that license
+published by that same organization.
+
+"Incorporate" means to publish or republish a Document, in whole or in
+part, as part of another Document.
+
+An MMC is "eligible for relicensing" if it is licensed under this
+License, and if all works that were first published under this License
+somewhere other than this MMC, and subsequently incorporated in whole or
+in part into the MMC, (1) had no cover texts or invariant sections, and
+(2) were thus incorporated prior to November 1, 2008.
+
+The operator of an MMC Site may republish an MMC contained in the site
+under CC-BY-SA on the same site at any time before August 1, 2009,
+provided the MMC is eligible for relicensing.
+
+
+ADDENDUM: How to use this License for your documents
+
+To use this License in a document you have written, include a copy of
+the License in the document and put the following copyright and
+license notices just after the title page:
+
+ Copyright (c) YEAR YOUR NAME.
+ Permission is granted to copy, distribute and/or modify this document
+ under the terms of the GNU Free Documentation License, Version 1.3
+ or any later version published by the Free Software Foundation;
+ with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
+ A copy of the license is included in the section entitled "GNU
+ Free Documentation License".
+
+If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts,
+replace the "with...Texts." line with this:
+
+ with the Invariant Sections being LIST THEIR TITLES, with the
+ Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
+
+If you have Invariant Sections without Cover Texts, or some other
+combination of the three, merge those two alternatives to suit the
+situation.
+
+If your document contains nontrivial examples of program code, we
+recommend releasing these examples in parallel under your choice of
+free software license, such as the GNU General Public License,
+to permit their use in free software.
diff --git a/LICENSE.LGPLv3 b/LICENSE.LGPLv3
new file mode 100644
index 000000000..e200fb5b2
--- /dev/null
+++ b/LICENSE.LGPLv3
@@ -0,0 +1,174 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+
+ The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd.
+ Contact: http://www.qt.io/licensing/
+
+ You may use, distribute and copy the Qt Toolkit under the terms of
+ GNU Lesser General Public License version 3, which is displayed below.
+ This license makes reference to the version 3 of the GNU General
+ Public License, which you can find in the LICENSE.GPLv3 file.
+
+-------------------------------------------------------------------------
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright © 2007 Free Software Foundation, Inc. <http://fsf.org/>
+Everyone is permitted to copy and distribute verbatim copies of this
+licensedocument, but changing it is not allowed.
+
+This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+0. Additional Definitions.
+
+ As used herein, “this License” refers to version 3 of the GNU Lesser
+General Public License, and the “GNU GPL” refers to version 3 of the
+GNU General Public License.
+
+ “The Library” refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An “Application” is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A “Combined Work” is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the “Linked
+Version”.
+
+ The “Minimal Corresponding Source” for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The “Corresponding Application Code” for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort
+ to ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this
+ license document.
+
+4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that, taken
+together, effectively do not restrict modification of the portions of
+the Library contained in the Combined Work and reverse engineering for
+debugging such modifications, if you also do each of the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this
+ license document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of
+ this License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with
+ the Library. A suitable mechanism is one that (a) uses at run
+ time a copy of the Library already present on the user's
+ computer system, and (b) will operate properly with a modified
+ version of the Library that is interface-compatible with the
+ Linked Version.
+
+ e) Provide Installation Information, but only if you would
+ otherwise be required to provide such information under section 6
+ of the GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the Application
+ with a modified version of the Linked Version. (If you use option
+ 4d0, the Installation Information must accompany the Minimal
+ Corresponding Source and Corresponding Application Code. If you
+ use option 4d1, you must provide the Installation Information in
+ the manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.)
+
+5. Combined Libraries.
+
+ You may place library facilities that are a work based on the Library
+side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities, conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of
+ it is a work based on the Library, and explaining where to find
+ the accompanying uncombined form of the same work.
+
+6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+as you received it specifies that a certain numbered version of the
+GNU Lesser General Public License “or any later version” applies to
+it, you have the option of following the terms and conditions either
+of that published version or of any later version published by the
+Free Software Foundation. If the Library as you received it does not
+specify a version number of the GNU Lesser General Public License,
+you may choose any version of the GNU Lesser General Public License
+ever published by the Free Software Foundation.
+
+If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the Library.
diff --git a/coin/qt-installer-package-config.json b/coin/qt-installer-package-config.json
new file mode 100644
index 000000000..f9584a100
--- /dev/null
+++ b/coin/qt-installer-package-config.json
@@ -0,0 +1,16 @@
+{
+ "version": "1",
+ "module-split": {
+ "qtpdf": [
+ "**/include/*QtPdf*/**/*",
+ "**/lib/cmake/Qt5Gui/*",
+ "**/lib/cmake/Qt5Pdf/*",
+ "**/lib/cmake/Qt5PdfWidgets/*",
+ "**/lib/pkgconfig/Qt5Pdf*",
+ "**/lib/libQt5Pdf*",
+ "**/mkspecs/modules/qt_lib_pdf*",
+ "**/plugins/imageformats/*",
+ "**/qml/QtQuick/**/*"
+ ]
+ }
+}
diff --git a/configure.json b/configure.json
index 8caad24f0..a5dbad35b 100644
--- a/configure.json
+++ b/configure.json
@@ -3,6 +3,8 @@
"src/buildtools",
"src/core",
"src/webengine",
- "src/webenginewidgets"
+ "src/webenginewidgets",
+ "src/pdf",
+ "src/pdfwidgets"
]
}
diff --git a/configure.pri b/configure.pri
index 3cfce71e0..f2c3620de 100644
--- a/configure.pri
+++ b/configure.pri
@@ -114,7 +114,7 @@ defineTest(qtwebengine_platformError) {
defineTest(qtConfTest_detectPlatform) {
QT_FOR_CONFIG += gui-private
- !linux:!win32:!macos {
+ !linux:!win32:!macos:!ios {
qtwebengine_platformError("Unknown platform. Qt WebEngine only supports Linux, Windows, and macOS.")
} else {
linux:qtwebengine_isLinuxPlatformSupported() {
@@ -126,6 +126,9 @@ defineTest(qtConfTest_detectPlatform) {
macos:qtwebengine_isMacOsPlatformSupported() {
$${1}.platform = "macos"
}
+ ios:qtwebengine_isMacOsPlatformSupported() {
+ $${1}.platform = "ios"
+ }
}
!isEmpty(platformError) {
@@ -423,21 +426,21 @@ defineTest(qtwebengine_isWindowsPlatformSupported) {
defineTest(qtwebengine_isMacOsPlatformSupported) {
# FIXME: Try to get it back down to 8.2 for building on OS X 10.11
!qtwebengine_isMinXcodeVersion(8, 3, 3) {
- qtwebengine_platformError("Using Xcode version $$QMAKE_XCODE_VERSION, but at least version 8.3.3 is required to build Qt WebEngine.")
+ qtwebengine_platformError("Using Xcode version $$QMAKE_XCODE_VERSION, but at least version 8.3.3 is required to build Qt WebEngine or Qt Pdf.")
return(false)
}
!clang|intel_icc {
- qtwebengine_platformError("Qt WebEngine on macOS requires Clang.")
+ qtwebengine_platformError("Qt WebEngine and Qt Pdf requires Clang.")
return(false)
}
# We require macOS 10.12 (darwin version 16.0.0) or newer.
darwin_major_version = $$section(QMAKE_HOST.version, ., 0, 0)
lessThan(darwin_major_version, 16) {
- qtwebengine_platformError("Building Qt WebEngine requires macOS version 10.12 or newer.")
+ qtwebengine_platformError("Building Qt WebEngine or Qt Pdf requires macOS version 10.12 or newer.")
return(false)
}
!qtwebengine_isMinOSXSDKVersion(10, 12): {
- qtwebengine_platformError("Building Qt WebEngine requires a macOS SDK version of 10.12 or newer. Current version is $${WEBENGINE_OSX_SDK_PRODUCT_VERSION}.")
+ qtwebengine_platformError("Building Qt WebEngine or Qt Pdf requires a macOS SDK version of 10.12 or newer. Current version is $${WEBENGINE_OSX_SDK_PRODUCT_VERSION}.")
return(false)
}
return(true)
diff --git a/examples/examples.pro b/examples/examples.pro
index 3dac9b0b7..b4f411aeb 100644
--- a/examples/examples.pro
+++ b/examples/examples.pro
@@ -3,3 +3,7 @@ TEMPLATE=subdirs
qtHaveModule(webengine): SUBDIRS += webengine
qtHaveModule(webenginewidgets): SUBDIRS += webenginewidgets
+
+qtHaveModule(pdfwidgets): SUBDIRS += pdfwidgets
+
+qtHaveModule(quick): qtHaveModule(pdf): qtHaveModule(pdfwidgets): SUBDIRS += pdf
diff --git a/examples/pdf/multipage/main.cpp b/examples/pdf/multipage/main.cpp
new file mode 100644
index 000000000..35aaa8c64
--- /dev/null
+++ b/examples/pdf/multipage/main.cpp
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char* argv[])
+{
+ QCoreApplication::setApplicationName("Qt Quick Multi-page PDF Viewer Example");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:///pdfviewer/viewer.qml")));
+ if (app.arguments().count() > 1) {
+ QUrl toLoad = QUrl::fromUserInput(app.arguments().at(1));
+ engine.rootObjects().first()->setProperty("source", toLoad);
+ } else {
+ engine.rootObjects().first()->setProperty("source", QStringLiteral("resources/test.pdf"));
+ }
+
+
+ return app.exec();
+}
diff --git a/examples/pdf/multipage/multipage.pro b/examples/pdf/multipage/multipage.pro
new file mode 100644
index 000000000..5df9e653d
--- /dev/null
+++ b/examples/pdf/multipage/multipage.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+
+QT += qml quick pdf widgets svg
+
+SOURCES += main.cpp
+
+RESOURCES += \
+ viewer.qrc
+EXAMPLE_FILES = \
+ viewer.qml
+
+target.path = $$[QT_INSTALL_EXAMPLES]/pdf/multipage
+INSTALLS += target
+
diff --git a/examples/pdf/multipage/resources/document-open.svg b/examples/pdf/multipage/resources/document-open.svg
new file mode 100644
index 000000000..bf23123a3
--- /dev/null
+++ b/examples/pdf/multipage/resources/document-open.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="m4 4v24h24l-1-1h-22v-13h5l3-3h14v16l1 1v-21h-10l-3-3z"
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/edit-clear.svg b/examples/pdf/multipage/resources/edit-clear.svg
new file mode 100644
index 000000000..1c35aaf04
--- /dev/null
+++ b/examples/pdf/multipage/resources/edit-clear.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 8 3 L 0.94335938 10.056641 L 0 11 L 0.94335938 11.943359 L 8 19 L 20.333984 19 L 22 19 L 22 3 L 20.333984 3 L 8 3 z M 11.320312 7 L 14 9.6796875 L 16.679688 7 L 18 8.3203125 L 15.320312 11 L 18 13.679688 L 16.679688 15 L 14 12.320312 L 11.320312 15 L 10 13.679688 L 12.679688 11 L 10 8.3203125 L 11.320312 7 z "
+ class="ColorScheme-Text"
+ transform="translate(1,1)"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/edit-copy.svg b/examples/pdf/multipage/resources/edit-copy.svg
new file mode 100644
index 000000000..9dd16877d
--- /dev/null
+++ b/examples/pdf/multipage/resources/edit-copy.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="m4 3v1 13h1 2 1v1 1h6l4-4v-1-7-1h-2v-3h-1-10-1m1 1h10v2h-7v1 9h-1-2v-12m4 3h8v7h-3-1v1 3h-4v-11"
+ class="ColorScheme-Text"
+ transform="translate(1,1)"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/edit-select-all.svg b/examples/pdf/multipage/resources/edit-select-all.svg
new file mode 100644
index 000000000..5f21950a0
--- /dev/null
+++ b/examples/pdf/multipage/resources/edit-select-all.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 5 L 4 8 L 5 8 L 5 5 L 8 5 L 8 4 L 5 4 L 4 4 z M 16 4 L 16 5 L 19 5 L 19 8 L 20 8 L 20 4 L 16 4 z M 6 6 L 6 11 L 11 11 L 11 6 L 6 6 z M 13 6 L 13 11 L 18 11 L 18 6 L 13 6 z M 7 7 L 10 7 L 10 10 L 7 10 L 7 7 z M 14 7 L 17 7 L 17 10 L 14 10 L 14 7 z M 6 13 L 6 18 L 11 18 L 11 13 L 6 13 z M 13 13 L 13 18 L 18 18 L 18 13 L 13 13 z M 7 14 L 10 14 L 10 17 L 7 17 L 7 14 z M 14 14 L 17 14 L 17 17 L 14 17 L 14 14 z M 4 16 L 4 20 L 5 20 L 8 20 L 8 19 L 5 19 L 5 16 L 4 16 z M 19 16 L 19 19 L 16 19 L 16 20 L 20 20 L 20 19 L 20 16 L 19 16 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/go-down-search.svg b/examples/pdf/multipage/resources/go-down-search.svg
new file mode 100644
index 000000000..ae17ab93b
--- /dev/null
+++ b/examples/pdf/multipage/resources/go-down-search.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4.7070312 8 L 4 8.7070312 L 10.125 14.832031 L 12 16.707031 L 13.875 14.832031 L 20 8.7070312 L 19.292969 8 L 13.167969 14.125 L 12 15.292969 L 10.832031 14.125 L 4.7070312 8 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/go-next-view-page.svg b/examples/pdf/multipage/resources/go-next-view-page.svg
new file mode 100644
index 000000000..e453ddbec
--- /dev/null
+++ b/examples/pdf/multipage/resources/go-next-view-page.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 8.7070312 4 L 8 4.7070312 L 14.125 10.832031 L 15.292969 12 L 14.125 13.167969 L 8 19.292969 L 8.7070312 20 L 14.832031 13.875 L 16.707031 12 L 14.832031 10.125 L 8.7070312 4 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/go-previous-view-page.svg b/examples/pdf/multipage/resources/go-previous-view-page.svg
new file mode 100644
index 000000000..b032309e9
--- /dev/null
+++ b/examples/pdf/multipage/resources/go-previous-view-page.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 15.292969 4 L 9.1679688 10.125 L 7.2929688 12 L 9.1679688 13.875 L 15.292969 20 L 16 19.292969 L 9.875 13.167969 L 8.7070312 12 L 9.875 10.832031 L 16 4.7070312 L 15.292969 4 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/go-up-search.svg b/examples/pdf/multipage/resources/go-up-search.svg
new file mode 100644
index 000000000..5cc155873
--- /dev/null
+++ b/examples/pdf/multipage/resources/go-up-search.svg
@@ -0,0 +1,8 @@
+<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ <path d="M4.707 16L4 15.293l8-8 8 8-.707.707L12 8.707" class="ColorScheme-Text" fill="currentColor"/>
+</svg>
diff --git a/examples/pdf/multipage/resources/rotate-left.svg b/examples/pdf/multipage/resources/rotate-left.svg
new file mode 100644
index 000000000..90ce53c9d
--- /dev/null
+++ b/examples/pdf/multipage/resources/rotate-left.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+ <g color="#000" font-weight="400" fill="#474747">
+ <path d="M2 9v1c0 .265.093.53.281.719l3.72 3.719 3.718-3.72c.188-.187.281-.453.281-.718V9H9c-.265 0-.53.093-.719.281l-2.28 2.281-2.282-2.28A1.015 1.015 0 0 0 3 9z"/>
+ <path d="M8.5 3A3.515 3.515 0 0 0 5 6.5V12h2V6.5C7 5.66 7.66 5 8.5 5H13V3z"/>
+ </g>
+</svg>
diff --git a/examples/pdf/multipage/resources/rotate-right.svg b/examples/pdf/multipage/resources/rotate-right.svg
new file mode 100644
index 000000000..7383d1c84
--- /dev/null
+++ b/examples/pdf/multipage/resources/rotate-right.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+ <g font-weight="400" fill="#474747">
+ <path d="M3 3v2h4.5C8.34 5 9 5.66 9 6.5V12h2V6.5C11 4.579 9.421 3 7.5 3z"/>
+ <path d="M6 9h1c.257 0 .529.13.719.313L10 11.592l2.281-2.28C12.471 9.13 12.743 9 13 9h1v1c0 .31-.09.552-.281.75L10 14.406 6.281 10.75C6.091 10.552 6 10.31 6 10z"/>
+ </g>
+</svg>
diff --git a/examples/pdf/multipage/resources/test.pdf b/examples/pdf/multipage/resources/test.pdf
new file mode 100644
index 000000000..a9dc1bc29
--- /dev/null
+++ b/examples/pdf/multipage/resources/test.pdf
Binary files differ
diff --git a/examples/pdf/multipage/resources/zoom-fit-best.svg b/examples/pdf/multipage/resources/zoom-fit-best.svg
new file mode 100644
index 000000000..adf302621
--- /dev/null
+++ b/examples/pdf/multipage/resources/zoom-fit-best.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 5 L 4 8 L 5 8 L 5 5 L 8 5 L 8 4 L 5 4 L 4 4 z M 12 4 L 10 6 L 14 6 L 12 4 z M 16 4 L 16 5 L 19 5 L 19 8 L 20 8 L 20 5 L 20 4 L 19 4 L 16 4 z M 7 7 L 7 17 L 17 17 L 17 7 L 7 7 z M 8 8 L 16 8 L 16 16 L 8 16 L 8 8 z M 6 10 L 4 12 L 6 14 L 6 10 z M 18 10 L 18 14 L 20 12 L 18 10 z M 4 16 L 4 19 L 4 20 L 8 20 L 8 19 L 5 19 L 5 16 L 4 16 z M 19 16 L 19 19 L 16 19 L 16 20 L 20 20 L 20 19 L 20 16 L 19 16 z M 10 18 L 12 20 L 14 18 L 10 18 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/zoom-fit-width.svg b/examples/pdf/multipage/resources/zoom-fit-width.svg
new file mode 100644
index 000000000..985ee5205
--- /dev/null
+++ b/examples/pdf/multipage/resources/zoom-fit-width.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 7 7 L 7 17 L 17 17 L 17 7 L 7 7 z M 8 8 L 16 8 L 16 16 L 8 16 L 8 8 z M 6 10 L 4 12 L 6 14 L 6 10 z M 18 10 L 18 14 L 20 12 L 18 10 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/zoom-in.svg b/examples/pdf/multipage/resources/zoom-in.svg
new file mode 100644
index 000000000..efdc9f17d
--- /dev/null
+++ b/examples/pdf/multipage/resources/zoom-in.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 6 L 5 6 L 5 5 L 6 5 L 6 4 L 4 4 z M 9 4 L 9 5 L 11 5 L 11 4 L 9 4 z M 13 4 L 13 5 L 15 5 L 15 4 L 13 4 z M 18 4 L 18 5 L 19 5 L 19 6 L 20 6 L 20 4 L 18 4 z M 12 8 L 12 9 L 14.292969 9 L 11 12.292969 L 11.707031 13 L 15 9.7070312 L 15 12 L 16 12 L 16 8 L 15 8 L 12 8 z M 4 9 L 4 11 L 5 11 L 5 9 L 4 9 z M 19 9 L 19 11 L 20 11 L 20 9 L 19 9 z M 19 13 L 19 15 L 20 15 L 20 13 L 19 13 z M 4 14 L 4 20 L 10 20 L 10 14 L 4 14 z M 5 15 L 9 15 L 9 19 L 5 19 L 5 15 z M 19 18 L 19 19 L 18 19 L 18 20 L 20 20 L 20 18 L 19 18 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/zoom-original.svg b/examples/pdf/multipage/resources/zoom-original.svg
new file mode 100644
index 000000000..1b4080a03
--- /dev/null
+++ b/examples/pdf/multipage/resources/zoom-original.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 5 L 4 7 L 5 7 L 5 5 L 7 5 L 7 4 L 5 4 L 4 4 z M 17 4 L 17 5 L 19 5 L 19 7 L 20 7 L 20 5 L 20 4 L 19 4 L 17 4 z M 6 6 L 6 18 L 18 18 L 18 6 L 6 6 z M 7 7 L 17 7 L 17 17 L 7 17 L 7 7 z M 4 17 L 4 19 L 4 20 L 7 20 L 7 19 L 5 19 L 5 17 L 4 17 z M 19 17 L 19 19 L 17 19 L 17 20 L 20 20 L 20 17 L 19 17 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/resources/zoom-out.svg b/examples/pdf/multipage/resources/zoom-out.svg
new file mode 100644
index 000000000..fcde9e526
--- /dev/null
+++ b/examples/pdf/multipage/resources/zoom-out.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 11 L 5 11 L 5 5 L 19 5 L 19 19 L 13 19 L 13 20 L 20 20 L 20 19 L 20 5 L 20 4 L 5 4 L 4 4 z M 15.292969 8 L 12 11.292969 L 12 9 L 11 9 L 11 13 L 12 13 L 15 13 L 15 12 L 12.707031 12 L 16 8.7070312 L 15.292969 8 z M 4 14 L 4 16 L 5 16 L 5 15 L 6 15 L 6 14 L 4 14 z M 8 14 L 8 15 L 9 15 L 9 16 L 10 16 L 10 14 L 8 14 z M 4 18 L 4 20 L 6 20 L 6 19 L 5 19 L 5 18 L 4 18 z M 9 18 L 9 19 L 8 19 L 8 20 L 10 20 L 10 18 L 9 18 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/multipage/viewer.qml b/examples/pdf/multipage/viewer.qml
new file mode 100644
index 000000000..bcb898a80
--- /dev/null
+++ b/examples/pdf/multipage/viewer.qml
@@ -0,0 +1,360 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQml 2.14 // workaround for QTBUG-82873
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Pdf 5.15
+import QtQuick.Shapes 1.14
+import QtQuick.Window 2.14
+import Qt.labs.platform 1.1 as Platform
+
+ApplicationWindow {
+ id: root
+ width: 800
+ height: 1024
+ color: "lightgrey"
+ title: document.title
+ visible: true
+ property string source // for main.cpp
+
+ header: ToolBar {
+ RowLayout {
+ anchors.fill: parent
+ anchors.rightMargin: 6
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.Open
+ icon.source: "resources/document-open.svg"
+ onTriggered: fileDialog.open()
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.ZoomIn
+ enabled: view.renderScale < 10
+ icon.source: "resources/zoom-in.svg"
+ onTriggered: view.renderScale *= Math.sqrt(2)
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.ZoomOut
+ enabled: view.renderScale > 0.1
+ icon.source: "resources/zoom-out.svg"
+ onTriggered: view.renderScale /= Math.sqrt(2)
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/zoom-fit-width.svg"
+ onTriggered: view.scaleToWidth(root.contentItem.width, root.contentItem.height)
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/zoom-fit-best.svg"
+ onTriggered: view.scaleToPage(root.contentItem.width, root.contentItem.height)
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: "Ctrl+0"
+ icon.source: "resources/zoom-original.svg"
+ onTriggered: view.resetScale()
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: "Ctrl+L"
+ icon.source: "resources/rotate-left.svg"
+ onTriggered: view.pageRotation -= 90
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: "Ctrl+R"
+ icon.source: "resources/rotate-right.svg"
+ onTriggered: view.pageRotation += 90
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-previous-view-page.svg"
+ enabled: view.backEnbled
+ onTriggered: view.back()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "go back"
+ }
+ SpinBox {
+ id: currentPageSB
+ from: 1
+ to: document.pageCount
+ editable: true
+ onValueModified: view.goToPage(value - 1)
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ onActivated: currentPageSB.value--
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ onActivated: currentPageSB.value++
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-next-view-page.svg"
+ enabled: view.forwardEnabled
+ onTriggered: view.forward()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "go forward"
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.SelectAll
+ icon.source: "resources/edit-select-all.svg"
+ onTriggered: view.selectAll()
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.Copy
+ icon.source: "resources/edit-copy.svg"
+ enabled: view.selectedText !== ""
+ onTriggered: view.copySelectionToClipboard()
+ }
+ }
+ Shortcut {
+ sequence: StandardKey.Find
+ onActivated: searchField.forceActiveFocus()
+ }
+ Shortcut {
+ sequence: StandardKey.Quit
+ onActivated: Qt.quit()
+ }
+ }
+ }
+
+ Platform.FileDialog {
+ id: fileDialog
+ title: "Open a PDF file"
+ nameFilters: [ "PDF files (*.pdf)" ]
+ onAccepted: document.source = file
+ }
+
+ Dialog {
+ id: passwordDialog
+ title: "Password"
+ standardButtons: Dialog.Ok | Dialog.Cancel
+ modal: true
+ closePolicy: Popup.CloseOnEscape
+ anchors.centerIn: parent
+ width: 300
+
+ TextField {
+ id: passwordField
+ placeholderText: qsTr("Please provide the password")
+ echoMode: TextInput.Password
+ width: parent.width
+ onAccepted: passwordDialog.accept()
+ }
+ onAccepted: document.password = passwordField.text
+ }
+
+ Dialog {
+ id: errorDialog
+ title: "Error loading " + document.source
+ standardButtons: Dialog.Ok
+ modal: true
+ closePolicy: Popup.CloseOnEscape
+ anchors.centerIn: parent
+ width: 300
+
+ Label {
+ id: errorField
+ text: document.error
+ }
+ }
+
+ PdfDocument {
+ id: document
+ source: Qt.resolvedUrl(root.source)
+ onStatusChanged: {
+ if (status === PdfDocument.Error) errorDialog.open()
+ view.document = (status === PdfDocument.Ready ? document : undefined)
+ }
+ onPasswordRequired: {
+ passwordDialog.open()
+ passwordField.forceActiveFocus()
+ }
+ }
+
+ PdfMultiPageView {
+ id: view
+ anchors.fill: parent
+ anchors.leftMargin: searchDrawer.position * searchDrawer.width
+ document: root.document
+ searchString: searchField.text
+ onCurrentPageChanged: currentPageSB.value = view.currentPage + 1
+ }
+
+ Drawer {
+ id: searchDrawer
+ edge: Qt.LeftEdge
+ modal: false
+ width: 300
+ y: root.header.height
+ height: view.height
+ dim: false
+ clip: true
+ ListView {
+ id: searchResultsList
+ anchors.fill: parent
+ anchors.margins: 2
+ model: view.searchModel
+ ScrollBar.vertical: ScrollBar { }
+ delegate: ItemDelegate {
+ width: parent ? parent.width : 0
+ RowLayout {
+ anchors.fill: parent
+ spacing: 0
+ Label {
+ text: "Page " + (page + 1) + ": "
+ }
+ Label {
+ text: contextBefore
+ elide: Text.ElideLeft
+ horizontalAlignment: Text.AlignRight
+ Layout.fillWidth: true
+ Layout.preferredWidth: parent.width / 2
+ }
+ Label {
+ font.bold: true
+ text: view.searchString
+ width: implicitWidth
+ }
+ Label {
+ text: contextAfter
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ Layout.preferredWidth: parent.width / 2
+ }
+ }
+ highlighted: ListView.isCurrentItem
+ onClicked: {
+ searchResultsList.currentIndex = index
+ view.goToLocation(page, location, 0)
+ view.searchModel.currentResult = indexOnPage
+ }
+ }
+ }
+ }
+
+ footer: ToolBar {
+ height: footerRow.implicitHeight
+ RowLayout {
+ id: footerRow
+ anchors.fill: parent
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-up-search.svg"
+ shortcut: StandardKey.FindPrevious
+ onTriggered: view.searchBack()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "find previous"
+ }
+ TextField {
+ id: searchField
+ placeholderText: "search"
+ Layout.minimumWidth: 150
+ Layout.fillWidth: true
+ onAccepted: searchDrawer.open()
+ Image {
+ visible: searchField.text !== ""
+ source: "resources/edit-clear.svg"
+ anchors {
+ right: parent.right
+ top: parent.top
+ bottom: parent.bottom
+ margins: 3
+ rightMargin: 5
+ }
+ TapHandler {
+ onTapped: searchField.clear()
+ }
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-down-search.svg"
+ shortcut: StandardKey.FindNext
+ onTriggered: view.searchForward()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "find next"
+ }
+ Label {
+ id: statusLabel
+ property size implicitPointSize: document.pagePointSize(view.currentPage)
+ text: "page " + (currentPageSB.value) + " of " + document.pageCount +
+ " scale " + view.renderScale.toFixed(2) +
+ " original " + implicitPointSize.width.toFixed(1) + "x" + implicitPointSize.height.toFixed(1) + " pt"
+ visible: document.pageCount > 0
+ }
+ }
+ }
+}
diff --git a/examples/pdf/multipage/viewer.qrc b/examples/pdf/multipage/viewer.qrc
new file mode 100644
index 000000000..ffca51679
--- /dev/null
+++ b/examples/pdf/multipage/viewer.qrc
@@ -0,0 +1,21 @@
+<RCC>
+ <qresource prefix="/pdfviewer">
+ <file>viewer.qml</file>
+ <file>resources/document-open.svg</file>
+ <file>resources/edit-clear.svg</file>
+ <file>resources/edit-copy.svg</file>
+ <file>resources/edit-select-all.svg</file>
+ <file>resources/go-down-search.svg</file>
+ <file>resources/go-next-view-page.svg</file>
+ <file>resources/go-previous-view-page.svg</file>
+ <file>resources/go-up-search.svg</file>
+ <file>resources/rotate-left.svg</file>
+ <file>resources/rotate-right.svg</file>
+ <file>resources/test.pdf</file>
+ <file>resources/zoom-in.svg</file>
+ <file>resources/zoom-fit-best.svg</file>
+ <file>resources/zoom-fit-width.svg</file>
+ <file>resources/zoom-original.svg</file>
+ <file>resources/zoom-out.svg</file>
+ </qresource>
+</RCC>
diff --git a/examples/pdf/pdf.pro b/examples/pdf/pdf.pro
new file mode 100644
index 000000000..7130f3560
--- /dev/null
+++ b/examples/pdf/pdf.pro
@@ -0,0 +1,3 @@
+TEMPLATE=subdirs
+
+SUBDIRS += pdfviewer multipage
diff --git a/examples/pdf/pdfviewer/main.cpp b/examples/pdf/pdfviewer/main.cpp
new file mode 100644
index 000000000..5f65e3061
--- /dev/null
+++ b/examples/pdf/pdfviewer/main.cpp
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QApplication>
+#include <QQmlApplicationEngine>
+
+int main(int argc, char* argv[])
+{
+ QCoreApplication::setApplicationName("Qt Quick PDF Viewer Example");
+ QCoreApplication::setOrganizationName("QtProject");
+ QCoreApplication::setApplicationVersion(QT_VERSION_STR);
+ QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
+ QApplication app(argc, argv);
+
+ QQmlApplicationEngine engine;
+ engine.load(QUrl(QStringLiteral("qrc:///pdfviewer/viewer.qml")));
+ if (app.arguments().count() > 1) {
+ QUrl toLoad = QUrl::fromUserInput(app.arguments().at(1));
+ engine.rootObjects().first()->setProperty("source", toLoad);
+ } else {
+ engine.rootObjects().first()->setProperty("source", QStringLiteral("resources/test.pdf"));
+ }
+
+ return app.exec();
+}
diff --git a/examples/pdf/pdfviewer/pdfviewer.pro b/examples/pdf/pdfviewer/pdfviewer.pro
new file mode 100644
index 000000000..b8817c9be
--- /dev/null
+++ b/examples/pdf/pdfviewer/pdfviewer.pro
@@ -0,0 +1,14 @@
+TEMPLATE = app
+
+QT += qml quick pdf widgets svg
+
+SOURCES += main.cpp
+
+RESOURCES += \
+ viewer.qrc
+EXAMPLE_FILES = \
+ viewer.qml
+
+target.path = $$[QT_INSTALL_EXAMPLES]/pdf/pdfviewer
+INSTALLS += target
+
diff --git a/examples/pdf/pdfviewer/resources/document-open.svg b/examples/pdf/pdfviewer/resources/document-open.svg
new file mode 100644
index 000000000..bf23123a3
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/document-open.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="m4 4v24h24l-1-1h-22v-13h5l3-3h14v16l1 1v-21h-10l-3-3z"
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/edit-clear.svg b/examples/pdf/pdfviewer/resources/edit-clear.svg
new file mode 100644
index 000000000..1c35aaf04
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/edit-clear.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 8 3 L 0.94335938 10.056641 L 0 11 L 0.94335938 11.943359 L 8 19 L 20.333984 19 L 22 19 L 22 3 L 20.333984 3 L 8 3 z M 11.320312 7 L 14 9.6796875 L 16.679688 7 L 18 8.3203125 L 15.320312 11 L 18 13.679688 L 16.679688 15 L 14 12.320312 L 11.320312 15 L 10 13.679688 L 12.679688 11 L 10 8.3203125 L 11.320312 7 z "
+ class="ColorScheme-Text"
+ transform="translate(1,1)"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/edit-copy.svg b/examples/pdf/pdfviewer/resources/edit-copy.svg
new file mode 100644
index 000000000..9dd16877d
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/edit-copy.svg
@@ -0,0 +1,15 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path
+ style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="m4 3v1 13h1 2 1v1 1h6l4-4v-1-7-1h-2v-3h-1-10-1m1 1h10v2h-7v1 9h-1-2v-12m4 3h8v7h-3-1v1 3h-4v-11"
+ class="ColorScheme-Text"
+ transform="translate(1,1)"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/edit-select-all.svg b/examples/pdf/pdfviewer/resources/edit-select-all.svg
new file mode 100644
index 000000000..5f21950a0
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/edit-select-all.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 5 L 4 8 L 5 8 L 5 5 L 8 5 L 8 4 L 5 4 L 4 4 z M 16 4 L 16 5 L 19 5 L 19 8 L 20 8 L 20 4 L 16 4 z M 6 6 L 6 11 L 11 11 L 11 6 L 6 6 z M 13 6 L 13 11 L 18 11 L 18 6 L 13 6 z M 7 7 L 10 7 L 10 10 L 7 10 L 7 7 z M 14 7 L 17 7 L 17 10 L 14 10 L 14 7 z M 6 13 L 6 18 L 11 18 L 11 13 L 6 13 z M 13 13 L 13 18 L 18 18 L 18 13 L 13 13 z M 7 14 L 10 14 L 10 17 L 7 17 L 7 14 z M 14 14 L 17 14 L 17 17 L 14 17 L 14 14 z M 4 16 L 4 20 L 5 20 L 8 20 L 8 19 L 5 19 L 5 16 L 4 16 z M 19 16 L 19 19 L 16 19 L 16 20 L 20 20 L 20 19 L 20 16 L 19 16 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/go-down-search.svg b/examples/pdf/pdfviewer/resources/go-down-search.svg
new file mode 100644
index 000000000..ae17ab93b
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/go-down-search.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4.7070312 8 L 4 8.7070312 L 10.125 14.832031 L 12 16.707031 L 13.875 14.832031 L 20 8.7070312 L 19.292969 8 L 13.167969 14.125 L 12 15.292969 L 10.832031 14.125 L 4.7070312 8 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/go-next-view-page.svg b/examples/pdf/pdfviewer/resources/go-next-view-page.svg
new file mode 100644
index 000000000..e453ddbec
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/go-next-view-page.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 8.7070312 4 L 8 4.7070312 L 14.125 10.832031 L 15.292969 12 L 14.125 13.167969 L 8 19.292969 L 8.7070312 20 L 14.832031 13.875 L 16.707031 12 L 14.832031 10.125 L 8.7070312 4 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/go-previous-view-page.svg b/examples/pdf/pdfviewer/resources/go-previous-view-page.svg
new file mode 100644
index 000000000..b032309e9
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/go-previous-view-page.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 15.292969 4 L 9.1679688 10.125 L 7.2929688 12 L 9.1679688 13.875 L 15.292969 20 L 16 19.292969 L 9.875 13.167969 L 8.7070312 12 L 9.875 10.832031 L 16 4.7070312 L 15.292969 4 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/go-up-search.svg b/examples/pdf/pdfviewer/resources/go-up-search.svg
new file mode 100644
index 000000000..5cc155873
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/go-up-search.svg
@@ -0,0 +1,8 @@
+<svg height="24" width="24" xmlns="http://www.w3.org/2000/svg">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ <path d="M4.707 16L4 15.293l8-8 8 8-.707.707L12 8.707" class="ColorScheme-Text" fill="currentColor"/>
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/rotate-left.svg b/examples/pdf/pdfviewer/resources/rotate-left.svg
new file mode 100644
index 000000000..90ce53c9d
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/rotate-left.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+ <g color="#000" font-weight="400" fill="#474747">
+ <path d="M2 9v1c0 .265.093.53.281.719l3.72 3.719 3.718-3.72c.188-.187.281-.453.281-.718V9H9c-.265 0-.53.093-.719.281l-2.28 2.281-2.282-2.28A1.015 1.015 0 0 0 3 9z"/>
+ <path d="M8.5 3A3.515 3.515 0 0 0 5 6.5V12h2V6.5C7 5.66 7.66 5 8.5 5H13V3z"/>
+ </g>
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/rotate-right.svg b/examples/pdf/pdfviewer/resources/rotate-right.svg
new file mode 100644
index 000000000..7383d1c84
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/rotate-right.svg
@@ -0,0 +1,6 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16">
+ <g font-weight="400" fill="#474747">
+ <path d="M3 3v2h4.5C8.34 5 9 5.66 9 6.5V12h2V6.5C11 4.579 9.421 3 7.5 3z"/>
+ <path d="M6 9h1c.257 0 .529.13.719.313L10 11.592l2.281-2.28C12.471 9.13 12.743 9 13 9h1v1c0 .31-.09.552-.281.75L10 14.406 6.281 10.75C6.091 10.552 6 10.31 6 10z"/>
+ </g>
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/test.pdf b/examples/pdf/pdfviewer/resources/test.pdf
new file mode 100644
index 000000000..a9dc1bc29
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/test.pdf
Binary files differ
diff --git a/examples/pdf/pdfviewer/resources/zoom-fit-best.svg b/examples/pdf/pdfviewer/resources/zoom-fit-best.svg
new file mode 100644
index 000000000..adf302621
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/zoom-fit-best.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 5 L 4 8 L 5 8 L 5 5 L 8 5 L 8 4 L 5 4 L 4 4 z M 12 4 L 10 6 L 14 6 L 12 4 z M 16 4 L 16 5 L 19 5 L 19 8 L 20 8 L 20 5 L 20 4 L 19 4 L 16 4 z M 7 7 L 7 17 L 17 17 L 17 7 L 7 7 z M 8 8 L 16 8 L 16 16 L 8 16 L 8 8 z M 6 10 L 4 12 L 6 14 L 6 10 z M 18 10 L 18 14 L 20 12 L 18 10 z M 4 16 L 4 19 L 4 20 L 8 20 L 8 19 L 5 19 L 5 16 L 4 16 z M 19 16 L 19 19 L 16 19 L 16 20 L 20 20 L 20 19 L 20 16 L 19 16 z M 10 18 L 12 20 L 14 18 L 10 18 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/zoom-fit-width.svg b/examples/pdf/pdfviewer/resources/zoom-fit-width.svg
new file mode 100644
index 000000000..985ee5205
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/zoom-fit-width.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#4d4d4d;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 7 7 L 7 17 L 17 17 L 17 7 L 7 7 z M 8 8 L 16 8 L 16 16 L 8 16 L 8 8 z M 6 10 L 4 12 L 6 14 L 6 10 z M 18 10 L 18 14 L 20 12 L 18 10 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/zoom-in.svg b/examples/pdf/pdfviewer/resources/zoom-in.svg
new file mode 100644
index 000000000..efdc9f17d
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/zoom-in.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 6 L 5 6 L 5 5 L 6 5 L 6 4 L 4 4 z M 9 4 L 9 5 L 11 5 L 11 4 L 9 4 z M 13 4 L 13 5 L 15 5 L 15 4 L 13 4 z M 18 4 L 18 5 L 19 5 L 19 6 L 20 6 L 20 4 L 18 4 z M 12 8 L 12 9 L 14.292969 9 L 11 12.292969 L 11.707031 13 L 15 9.7070312 L 15 12 L 16 12 L 16 8 L 15 8 L 12 8 z M 4 9 L 4 11 L 5 11 L 5 9 L 4 9 z M 19 9 L 19 11 L 20 11 L 20 9 L 19 9 z M 19 13 L 19 15 L 20 15 L 20 13 L 19 13 z M 4 14 L 4 20 L 10 20 L 10 14 L 4 14 z M 5 15 L 9 15 L 9 19 L 5 19 L 5 15 z M 19 18 L 19 19 L 18 19 L 18 20 L 20 20 L 20 18 L 19 18 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/zoom-original.svg b/examples/pdf/pdfviewer/resources/zoom-original.svg
new file mode 100644
index 000000000..1b4080a03
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/zoom-original.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 5 L 4 7 L 5 7 L 5 5 L 7 5 L 7 4 L 5 4 L 4 4 z M 17 4 L 17 5 L 19 5 L 19 7 L 20 7 L 20 5 L 20 4 L 19 4 L 17 4 z M 6 6 L 6 18 L 18 18 L 18 6 L 6 6 z M 7 7 L 17 7 L 17 17 L 7 17 L 7 7 z M 4 17 L 4 19 L 4 20 L 7 20 L 7 19 L 5 19 L 5 17 L 4 17 z M 19 17 L 19 19 L 17 19 L 17 20 L 20 20 L 20 17 L 19 17 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/resources/zoom-out.svg b/examples/pdf/pdfviewer/resources/zoom-out.svg
new file mode 100644
index 000000000..fcde9e526
--- /dev/null
+++ b/examples/pdf/pdfviewer/resources/zoom-out.svg
@@ -0,0 +1,13 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
+ <defs id="defs3051">
+ <style type="text/css" id="current-color-scheme">
+ .ColorScheme-Text {
+ color:#232629;
+ }
+ </style>
+ </defs>
+ <path style="fill:currentColor;fill-opacity:1;stroke:none"
+ d="M 4 4 L 4 11 L 5 11 L 5 5 L 19 5 L 19 19 L 13 19 L 13 20 L 20 20 L 20 19 L 20 5 L 20 4 L 5 4 L 4 4 z M 15.292969 8 L 12 11.292969 L 12 9 L 11 9 L 11 13 L 12 13 L 15 13 L 15 12 L 12.707031 12 L 16 8.7070312 L 15.292969 8 z M 4 14 L 4 16 L 5 16 L 5 15 L 6 15 L 6 14 L 4 14 z M 8 14 L 8 15 L 9 15 L 9 16 L 10 16 L 10 14 L 8 14 z M 4 18 L 4 20 L 6 20 L 6 19 L 5 19 L 5 18 L 4 18 z M 9 18 L 9 19 L 8 19 L 8 20 L 10 20 L 10 18 L 9 18 z "
+ class="ColorScheme-Text"
+ />
+</svg>
diff --git a/examples/pdf/pdfviewer/viewer.qml b/examples/pdf/pdfviewer/viewer.qml
new file mode 100644
index 000000000..f4c913154
--- /dev/null
+++ b/examples/pdf/pdfviewer/viewer.qml
@@ -0,0 +1,335 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQml 2.14 // workaround for QTBUG-82873
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Pdf 5.15
+import QtQuick.Shapes 1.14
+import QtQuick.Window 2.14
+import Qt.labs.animation 1.0
+import Qt.labs.platform 1.1 as Platform
+
+ApplicationWindow {
+ id: root
+ width: 800
+ height: 1024
+ color: "lightgrey"
+ title: document.title
+ visible: true
+ property string source // for main.cpp
+ property real scaleStep: Math.sqrt(2)
+
+ header: ToolBar {
+ RowLayout {
+ anchors.fill: parent
+ anchors.rightMargin: 6
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.Open
+ icon.source: "resources/document-open.svg"
+ onTriggered: fileDialog.open()
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.ZoomIn
+ enabled: view.sourceSize.width < 10000
+ icon.source: "resources/zoom-in.svg"
+ onTriggered: view.renderScale *= root.scaleStep
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.ZoomOut
+ enabled: view.sourceSize.width > 50
+ icon.source: "resources/zoom-out.svg"
+ onTriggered: view.renderScale /= root.scaleStep
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/zoom-fit-width.svg"
+ onTriggered: view.scaleToWidth(root.contentItem.width, root.contentItem.height)
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/zoom-fit-best.svg"
+ onTriggered: view.scaleToPage(root.contentItem.width, root.contentItem.height)
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: "Ctrl+0"
+ icon.source: "resources/zoom-original.svg"
+ onTriggered: view.resetScale()
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: "Ctrl+L"
+ icon.source: "resources/rotate-left.svg"
+ onTriggered: view.pageRotation -= 90
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: "Ctrl+R"
+ icon.source: "resources/rotate-right.svg"
+ onTriggered: view.pageRotation += 90
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-previous-view-page.svg"
+ enabled: view.backEnabled
+ onTriggered: view.back()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "go back"
+ }
+ SpinBox {
+ id: currentPageSB
+ from: 1
+ to: document.pageCount
+ editable: true
+ value: view.currentPage + 1
+ onValueModified: view.goToPage(value - 1)
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ onActivated: view.goToPage(currentPageSB.value - 2)
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ onActivated: view.goToPage(currentPageSB.value)
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-next-view-page.svg"
+ enabled: view.forwardEnabled
+ onTriggered: view.forward()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "go forward"
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.SelectAll
+ icon.source: "resources/edit-select-all.svg"
+ onTriggered: view.selectAll()
+ }
+ }
+ ToolButton {
+ action: Action {
+ shortcut: StandardKey.Copy
+ icon.source: "resources/edit-copy.svg"
+ enabled: view.selectedText !== ""
+ onTriggered: view.copySelectionToClipboard()
+ }
+ }
+ Shortcut {
+ sequence: StandardKey.Find
+ onActivated: searchField.forceActiveFocus()
+ }
+ Shortcut {
+ sequence: StandardKey.Quit
+ onActivated: Qt.quit()
+ }
+ }
+ }
+
+ Platform.FileDialog {
+ id: fileDialog
+ title: "Open a PDF file"
+ nameFilters: [ "PDF files (*.pdf)" ]
+ onAccepted: document.source = file
+ }
+
+ Dialog {
+ id: errorDialog
+ title: "Error loading " + document.source
+ standardButtons: Dialog.Ok
+ modal: true
+ closePolicy: Popup.CloseOnEscape
+ anchors.centerIn: parent
+ width: 300
+
+ Label {
+ id: errorField
+ text: document.error
+ }
+ }
+
+ PdfScrollablePageView {
+ id: view
+ anchors.fill: parent
+ anchors.leftMargin: searchDrawer.position * searchDrawer.width
+ document: PdfDocument {
+ id: document
+ source: Qt.resolvedUrl(root.source)
+ onStatusChanged: if (status === PdfDocument.Error) errorDialog.open()
+ }
+ searchString: searchField.text
+ }
+
+ Drawer {
+ id: searchDrawer
+ edge: Qt.LeftEdge
+ modal: false
+ width: 300
+ y: root.header.height
+ height: view.height
+ dim: false
+ clip: true
+ ListView {
+ id: searchResultsList
+ anchors.fill: parent
+ anchors.margins: 2
+ model: view.searchModel
+ ScrollBar.vertical: ScrollBar { }
+ delegate: ItemDelegate {
+ width: parent ? parent.width : 0
+ RowLayout {
+ anchors.fill: parent
+ spacing: 0
+ Label {
+ text: "Page " + (page + 1) + ": "
+ }
+ Label {
+ text: contextBefore
+ elide: Text.ElideLeft
+ horizontalAlignment: Text.AlignRight
+ Layout.fillWidth: true
+ Layout.preferredWidth: parent.width / 2
+ }
+ Label {
+ font.bold: true
+ text: view.searchString
+ width: implicitWidth
+ }
+ Label {
+ text: contextAfter
+ elide: Text.ElideRight
+ Layout.fillWidth: true
+ Layout.preferredWidth: parent.width / 2
+ }
+ }
+ highlighted: ListView.isCurrentItem
+ onClicked: {
+ searchResultsList.currentIndex = index
+ view.goToLocation(page, location, 0)
+ view.searchModel.currentResult = indexOnPage
+ }
+ }
+ }
+ }
+
+ footer: ToolBar {
+ height: footerRow.implicitHeight
+ RowLayout {
+ id: footerRow
+ anchors.fill: parent
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-up-search.svg"
+ shortcut: StandardKey.FindPrevious
+ onTriggered: view.searchBack()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "find previous"
+ }
+ TextField {
+ id: searchField
+ placeholderText: "search"
+ Layout.minimumWidth: 150
+ Layout.maximumWidth: 300
+ Layout.fillWidth: true
+ onAccepted: searchDrawer.open()
+ Image {
+ visible: searchField.text !== ""
+ source: "resources/edit-clear.svg"
+ anchors {
+ right: parent.right
+ top: parent.top
+ bottom: parent.bottom
+ margins: 3
+ rightMargin: 5
+ }
+ TapHandler {
+ onTapped: searchField.clear()
+ }
+ }
+ }
+ ToolButton {
+ action: Action {
+ icon.source: "resources/go-down-search.svg"
+ shortcut: StandardKey.FindNext
+ onTriggered: view.searchForward()
+ }
+ ToolTip.visible: enabled && hovered
+ ToolTip.delay: 2000
+ ToolTip.text: "find next"
+ }
+ Label {
+ Layout.fillWidth: true
+ property size implicitPointSize: document.pagePointSize(view.currentPage)
+ text: "page " + (view.currentPage + 1) + " of " + document.pageCount +
+ " scale " + view.renderScale.toFixed(2) +
+ " original " + implicitPointSize.width.toFixed(1) + "x" + implicitPointSize.height.toFixed(1) + "pts"
+ visible: document.status === PdfDocument.Ready
+ }
+ }
+ }
+}
diff --git a/examples/pdf/pdfviewer/viewer.qrc b/examples/pdf/pdfviewer/viewer.qrc
new file mode 100644
index 000000000..ffca51679
--- /dev/null
+++ b/examples/pdf/pdfviewer/viewer.qrc
@@ -0,0 +1,21 @@
+<RCC>
+ <qresource prefix="/pdfviewer">
+ <file>viewer.qml</file>
+ <file>resources/document-open.svg</file>
+ <file>resources/edit-clear.svg</file>
+ <file>resources/edit-copy.svg</file>
+ <file>resources/edit-select-all.svg</file>
+ <file>resources/go-down-search.svg</file>
+ <file>resources/go-next-view-page.svg</file>
+ <file>resources/go-previous-view-page.svg</file>
+ <file>resources/go-up-search.svg</file>
+ <file>resources/rotate-left.svg</file>
+ <file>resources/rotate-right.svg</file>
+ <file>resources/test.pdf</file>
+ <file>resources/zoom-in.svg</file>
+ <file>resources/zoom-fit-best.svg</file>
+ <file>resources/zoom-fit-width.svg</file>
+ <file>resources/zoom-original.svg</file>
+ <file>resources/zoom-out.svg</file>
+ </qresource>
+</RCC>
diff --git a/examples/pdfwidgets/pdfviewer/doc/src/pdfviewer.qdoc b/examples/pdfwidgets/pdfviewer/doc/src/pdfviewer.qdoc
new file mode 100644
index 000000000..9c7b3deed
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/doc/src/pdfviewer.qdoc
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example pdfviewer
+ \ingroup qtpdf-examples
+
+ \title PDF Viewer Example
+ \brief Renders PDF documents.
+
+ \image pdfviewer.png
+
+ \e {PDF Viewer} demonstrates how to use the \l QPdfDocument class to render
+ PDF documents and the \l QPdfPageNavigation class to navigate them.
+
+ Qt Creator and the integrated Qt Designer were used to create the example
+ UI and to connect it to the code. This affects the code, which might be
+ somewhat different to what you would typically write by hand.
+ For more information about using Qt Designer, see \l{Qt Designer Manual}
+ and \l{Qt Creator: Creating a Qt Widget Based Application}.
+
+ \include examples-run.qdocinc
+
+ \section1 Creating the Main Window
+
+ The MainWindow class inherits the QMainWindow class:
+
+ \quotefromfile pdfviewer/mainwindow.h
+ \skipto public QMainWindow
+ \printuntil ~MainWindow()
+
+ The class declares public and private slots that match the actions of the
+ selectors:
+
+ \printuntil on_actionContinuous_triggered()
+
+ The actual layout of the main window is specified in a \c{.ui} file. The
+ widgets and actions are available at runtime in the \c ui member variable.
+
+ \printuntil Ui::
+
+ The \c m_zoomSelector variable holds the zoom selector and the
+ \c m_pageSelector holds the page selector. The \c m_document
+ variable is an instance of the QPdfDocument class that contains
+ the PDF document.
+
+ \printuntil }
+
+ The actual setup of the different objects is done in the MainWindow
+ constructor:
+
+ \quotefromfile pdfviewer/mainwindow.cpp
+ \skipto MainWindow::
+ \printuntil {
+
+ The constructor first calls \c setupUi() to construct the zoom and page
+ selectors according to the UI file. We set the maximum width of the
+ selectors.
+
+ \printuntil addWidget(m_pageSelector)
+
+ We use the \l QPdfPageNavigation class to handle the navigation through a
+ PDF document:
+
+ \printuntil setPageNavigation
+
+ We connect the \c zoomModeChanged and \c zoomFactor changed signals of the
+ PDF view to the functions that reset the zoom selector:
+
+ \printuntil reset()
+
+ We then load the PDF document to the viewer:
+
+ \dots
+ \skipto pdfView
+ \printuntil ;
+
+ Finally, we connect the \c zoomFactorChanged signal to the function that
+ sets the value of the zoom selector:
+
+ \printuntil }
+
+ \section1 Files and Attributions
+*/
diff --git a/examples/pdfwidgets/pdfviewer/images/busy.png b/examples/pdfwidgets/pdfviewer/images/busy.png
new file mode 100644
index 000000000..69056c479
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/busy.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/fileopen.png b/examples/pdfwidgets/pdfviewer/images/fileopen.png
new file mode 100644
index 000000000..33e0d6394
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/fileopen.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/go-next-24.png b/examples/pdfwidgets/pdfviewer/images/go-next-24.png
new file mode 100644
index 000000000..9a55ef3d8
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/go-next-24.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/go-previous-24.png b/examples/pdfwidgets/pdfviewer/images/go-previous-24.png
new file mode 100644
index 000000000..2ea769eb8
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/go-previous-24.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/zoom-in-24.png b/examples/pdfwidgets/pdfviewer/images/zoom-in-24.png
new file mode 100644
index 000000000..d29b142b6
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/zoom-in-24.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/zoom-in-32.png b/examples/pdfwidgets/pdfviewer/images/zoom-in-32.png
new file mode 100644
index 000000000..34d70af37
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/zoom-in-32.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/zoom-out-24.png b/examples/pdfwidgets/pdfviewer/images/zoom-out-24.png
new file mode 100644
index 000000000..19703474f
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/zoom-out-24.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/images/zoom-out-32.png b/examples/pdfwidgets/pdfviewer/images/zoom-out-32.png
new file mode 100644
index 000000000..b83220661
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/images/zoom-out-32.png
Binary files differ
diff --git a/examples/pdfwidgets/pdfviewer/main.cpp b/examples/pdfwidgets/pdfviewer/main.cpp
new file mode 100644
index 000000000..20fa6f8cd
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/main.cpp
@@ -0,0 +1,51 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include <QApplication>
+#include <QUrl>
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ MainWindow w;
+ QStringList args = a.arguments();
+ w.show();
+ if (args.length() > 1)
+ w.open(QUrl::fromLocalFile(args[1]));
+
+ return a.exec();
+}
diff --git a/examples/pdfwidgets/pdfviewer/mainwindow.cpp b/examples/pdfwidgets/pdfviewer/mainwindow.cpp
new file mode 100644
index 000000000..5f9bf389f
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/mainwindow.cpp
@@ -0,0 +1,162 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+
+#include "pageselector.h"
+#include "zoomselector.h"
+
+#include <QFileDialog>
+#include <QMessageBox>
+#include <QPdfBookmarkModel>
+#include <QPdfDocument>
+#include <QPdfPageNavigation>
+#include <QtMath>
+
+const qreal zoomMultiplier = qSqrt(2.0);
+
+Q_LOGGING_CATEGORY(lcExample, "qt.examples.pdfviewer")
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindow)
+ , m_zoomSelector(new ZoomSelector(this))
+ , m_pageSelector(new PageSelector(this))
+ , m_document(new QPdfDocument(this))
+{
+ ui->setupUi(this);
+
+ m_zoomSelector->setMaximumWidth(150);
+ ui->mainToolBar->insertWidget(ui->actionZoom_In, m_zoomSelector);
+
+ m_pageSelector->setMaximumWidth(150);
+ ui->mainToolBar->addWidget(m_pageSelector);
+
+ m_pageSelector->setPageNavigation(ui->pdfView->pageNavigation());
+
+ connect(m_zoomSelector, &ZoomSelector::zoomModeChanged, ui->pdfView, &QPdfView::setZoomMode);
+ connect(m_zoomSelector, &ZoomSelector::zoomFactorChanged, ui->pdfView, &QPdfView::setZoomFactor);
+ m_zoomSelector->reset();
+
+ QPdfBookmarkModel *bookmarkModel = new QPdfBookmarkModel(this);
+ bookmarkModel->setDocument(m_document);
+
+ ui->bookmarkView->setModel(bookmarkModel);
+ connect(ui->bookmarkView, SIGNAL(activated(QModelIndex)), this, SLOT(bookmarkSelected(QModelIndex)));
+
+ ui->tabWidget->setTabEnabled(1, false); // disable 'Pages' tab for now
+
+ ui->pdfView->setDocument(m_document);
+
+ connect(ui->pdfView, &QPdfView::zoomFactorChanged,
+ m_zoomSelector, &ZoomSelector::setZoomFactor);
+}
+
+MainWindow::~MainWindow()
+{
+ delete ui;
+}
+
+void MainWindow::open(const QUrl &docLocation)
+{
+ if (docLocation.isLocalFile()) {
+ m_document->load(docLocation.toLocalFile());
+ const auto documentTitle = m_document->metaData(QPdfDocument::Title).toString();
+ setWindowTitle(!documentTitle.isEmpty() ? documentTitle : QStringLiteral("PDF Viewer"));
+ } else {
+ qCDebug(lcExample) << docLocation << "is not a valid local file";
+ QMessageBox::critical(this, tr("Failed to open"), tr("%1 is not a valid local file").arg(docLocation.toString()));
+ }
+ qCDebug(lcExample) << docLocation;
+}
+
+void MainWindow::bookmarkSelected(const QModelIndex &index)
+{
+ if (!index.isValid())
+ return;
+
+ const int page = index.data(QPdfBookmarkModel::PageNumberRole).toInt();
+ ui->pdfView->pageNavigation()->setCurrentPage(page);
+}
+
+void MainWindow::on_actionOpen_triggered()
+{
+ QUrl toOpen = QFileDialog::getOpenFileUrl(this, tr("Choose a PDF"), QUrl(), "Portable Documents (*.pdf)");
+ if (toOpen.isValid())
+ open(toOpen);
+}
+
+void MainWindow::on_actionQuit_triggered()
+{
+ QApplication::quit();
+}
+
+void MainWindow::on_actionAbout_triggered()
+{
+ QMessageBox::about(this, tr("About PdfViewer"),
+ tr("An example using QPdfDocument"));
+}
+
+void MainWindow::on_actionAbout_Qt_triggered()
+{
+ QMessageBox::aboutQt(this);
+}
+
+void MainWindow::on_actionZoom_In_triggered()
+{
+ ui->pdfView->setZoomFactor(ui->pdfView->zoomFactor() * zoomMultiplier);
+}
+
+void MainWindow::on_actionZoom_Out_triggered()
+{
+ ui->pdfView->setZoomFactor(ui->pdfView->zoomFactor() / zoomMultiplier);
+}
+
+void MainWindow::on_actionPrevious_Page_triggered()
+{
+ ui->pdfView->pageNavigation()->goToPreviousPage();
+}
+
+void MainWindow::on_actionNext_Page_triggered()
+{
+ ui->pdfView->pageNavigation()->goToNextPage();
+}
+
+void MainWindow::on_actionContinuous_triggered()
+{
+ ui->pdfView->setPageMode(ui->actionContinuous->isChecked() ? QPdfView::MultiPage : QPdfView::SinglePage);
+}
diff --git a/examples/pdfwidgets/pdfviewer/mainwindow.h b/examples/pdfwidgets/pdfviewer/mainwindow.h
new file mode 100644
index 000000000..afdfcade4
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/mainwindow.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QLoggingCategory>
+#include <QMainWindow>
+
+Q_DECLARE_LOGGING_CATEGORY(lcExample)
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class MainWindow;
+}
+
+class QPdfDocument;
+class QPdfView;
+QT_END_NAMESPACE
+
+class PageSelector;
+class ZoomSelector;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = nullptr);
+ ~MainWindow();
+
+public slots:
+ void open(const QUrl &docLocation);
+
+private slots:
+ void bookmarkSelected(const QModelIndex &index);
+
+ // action handlers
+ void on_actionOpen_triggered();
+ void on_actionQuit_triggered();
+ void on_actionAbout_triggered();
+ void on_actionAbout_Qt_triggered();
+ void on_actionZoom_In_triggered();
+ void on_actionZoom_Out_triggered();
+ void on_actionPrevious_Page_triggered();
+ void on_actionNext_Page_triggered();
+ void on_actionContinuous_triggered();
+
+private:
+ Ui::MainWindow *ui;
+ ZoomSelector *m_zoomSelector;
+ PageSelector *m_pageSelector;
+
+ QPdfDocument *m_document;
+};
+
+#endif // MAINWINDOW_H
diff --git a/examples/pdfwidgets/pdfviewer/mainwindow.ui b/examples/pdfwidgets/pdfviewer/mainwindow.ui
new file mode 100644
index 000000000..2651525a5
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/mainwindow.ui
@@ -0,0 +1,281 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QMainWindow" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>700</width>
+ <height>600</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>PDF Viewer</string>
+ </property>
+ <property name="unifiedTitleAndToolBarOnMac">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="centralWidget">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QWidget" name="widget" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QSplitter" name="splitter">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="tabPosition">
+ <enum>QTabWidget::West</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="documentMode">
+ <bool>false</bool>
+ </property>
+ <widget class="QWidget" name="bookmarkTab">
+ <attribute name="title">
+ <string>Bookmarks</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <property name="spacing">
+ <number>0</number>
+ </property>
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
+ <number>2</number>
+ </property>
+ <item>
+ <widget class="QTreeView" name="bookmarkView">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="headerHidden">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="pagesTab">
+ <attribute name="title">
+ <string>Pages</string>
+ </attribute>
+ </widget>
+ </widget>
+ <widget class="QPdfView" name="pdfView" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="menuBar">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>700</width>
+ <height>22</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="menuFile">
+ <property name="title">
+ <string>File</string>
+ </property>
+ <addaction name="actionOpen"/>
+ <addaction name="actionQuit"/>
+ </widget>
+ <widget class="QMenu" name="menuHelp">
+ <property name="title">
+ <string>Help</string>
+ </property>
+ <addaction name="actionAbout"/>
+ <addaction name="actionAbout_Qt"/>
+ </widget>
+ <widget class="QMenu" name="menuView">
+ <property name="title">
+ <string>View</string>
+ </property>
+ <addaction name="actionZoom_In"/>
+ <addaction name="actionZoom_Out"/>
+ <addaction name="actionPrevious_Page"/>
+ <addaction name="actionNext_Page"/>
+ <addaction name="separator"/>
+ <addaction name="actionContinuous"/>
+ </widget>
+ <addaction name="menuFile"/>
+ <addaction name="menuView"/>
+ <addaction name="menuHelp"/>
+ </widget>
+ <widget class="QToolBar" name="mainToolBar">
+ <property name="movable">
+ <bool>false</bool>
+ </property>
+ <property name="floatable">
+ <bool>false</bool>
+ </property>
+ <attribute name="toolBarArea">
+ <enum>TopToolBarArea</enum>
+ </attribute>
+ <attribute name="toolBarBreak">
+ <bool>false</bool>
+ </attribute>
+ <addaction name="actionOpen"/>
+ <addaction name="separator"/>
+ <addaction name="actionZoom_Out"/>
+ <addaction name="actionZoom_In"/>
+ <addaction name="separator"/>
+ </widget>
+ <widget class="QStatusBar" name="statusBar"/>
+ <action name="actionOpen">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/images/fileopen.png</normaloff>:/icons/images/fileopen.png</iconset>
+ </property>
+ <property name="text">
+ <string>Open...</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+O</string>
+ </property>
+ </action>
+ <action name="actionQuit">
+ <property name="text">
+ <string>Quit</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="actionAbout">
+ <property name="text">
+ <string>About</string>
+ </property>
+ </action>
+ <action name="actionAbout_Qt">
+ <property name="text">
+ <string>About Qt</string>
+ </property>
+ </action>
+ <action name="actionZoom_In">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/images/zoom-in-24.png</normaloff>:/icons/images/zoom-in-24.png</iconset>
+ </property>
+ <property name="text">
+ <string>Zoom In</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+=</string>
+ </property>
+ </action>
+ <action name="actionZoom_Out">
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/icons/images/zoom-out-24.png</normaloff>:/icons/images/zoom-out-24.png</iconset>
+ </property>
+ <property name="text">
+ <string>Zoom Out</string>
+ </property>
+ <property name="shortcut">
+ <string>Ctrl+-</string>
+ </property>
+ </action>
+ <action name="actionPrevious_Page">
+ <property name="text">
+ <string>Previous Page</string>
+ </property>
+ <property name="shortcut">
+ <string>PgUp</string>
+ </property>
+ </action>
+ <action name="actionNext_Page">
+ <property name="text">
+ <string>Next Page</string>
+ </property>
+ <property name="shortcut">
+ <string>PgDown</string>
+ </property>
+ </action>
+ <action name="actionContinuous">
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Continuous</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11"/>
+ <customwidgets>
+ <customwidget>
+ <class>QPdfView</class>
+ <extends>QWidget</extends>
+ <header location="global">qpdfview.h</header>
+ <container>1</container>
+ </customwidget>
+ </customwidgets>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/examples/pdfwidgets/pdfviewer/pageselector.cpp b/examples/pdfwidgets/pdfviewer/pageselector.cpp
new file mode 100644
index 000000000..cd3c4ba0e
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/pageselector.cpp
@@ -0,0 +1,111 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "pageselector.h"
+
+#include <QHBoxLayout>
+#include <QLabel>
+#include <QLineEdit>
+#include <QPdfPageNavigation>
+#include <QToolButton>
+
+PageSelector::PageSelector(QWidget *parent)
+ : QWidget(parent)
+ , m_pageNavigation(nullptr)
+{
+ QHBoxLayout *layout = new QHBoxLayout(this);
+
+ m_previousPageButton = new QToolButton(this);
+ m_previousPageButton->setText("<");
+ m_previousPageButton->setEnabled(false);
+
+ m_pageNumberEdit = new QLineEdit(this);
+ m_pageNumberEdit->setAlignment(Qt::AlignRight);
+
+ m_pageCountLabel = new QLabel(this);
+ m_pageCountLabel->setText("0");
+
+ m_nextPageButton = new QToolButton(this);
+ m_nextPageButton->setText(">");
+ m_nextPageButton->setEnabled(false);
+
+ layout->addWidget(m_previousPageButton);
+ layout->addWidget(m_pageNumberEdit);
+ layout->addWidget(m_pageCountLabel);
+ layout->addWidget(m_nextPageButton);
+}
+
+void PageSelector::setPageNavigation(QPdfPageNavigation *pageNavigation)
+{
+ m_pageNavigation = pageNavigation;
+
+ connect(m_previousPageButton, &QToolButton::clicked, m_pageNavigation, &QPdfPageNavigation::goToPreviousPage);
+ connect(m_pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged, m_previousPageButton, &QToolButton::setEnabled);
+
+ connect(m_pageNavigation, &QPdfPageNavigation::currentPageChanged, this, &PageSelector::onCurrentPageChanged);
+ connect(m_pageNavigation, &QPdfPageNavigation::pageCountChanged, this, [this](int pageCount){ m_pageCountLabel->setText(QString::fromLatin1("/ %1").arg(pageCount)); });
+
+ connect(m_pageNumberEdit, &QLineEdit::editingFinished, this, &PageSelector::pageNumberEdited);
+
+ connect(m_nextPageButton, &QToolButton::clicked, m_pageNavigation, &QPdfPageNavigation::goToNextPage);
+ connect(m_pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged, m_nextPageButton, &QToolButton::setEnabled);
+
+ onCurrentPageChanged(m_pageNavigation->currentPage());
+}
+
+void PageSelector::onCurrentPageChanged(int page)
+{
+ if (m_pageNavigation->pageCount() == 0)
+ m_pageNumberEdit->setText(QString::number(0));
+ else
+ m_pageNumberEdit->setText(QString::number(page + 1));
+}
+
+void PageSelector::pageNumberEdited()
+{
+ if (!m_pageNavigation)
+ return;
+
+ const QString text = m_pageNumberEdit->text();
+
+ bool ok = false;
+ const int pageNumber = text.toInt(&ok);
+
+ if (!ok)
+ onCurrentPageChanged(m_pageNavigation->currentPage());
+ else
+ m_pageNavigation->setCurrentPage(qBound(0, pageNumber - 1, m_pageNavigation->pageCount() - 1));
+}
diff --git a/examples/pdfwidgets/pdfviewer/pageselector.h b/examples/pdfwidgets/pdfviewer/pageselector.h
new file mode 100644
index 000000000..7a7283f99
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/pageselector.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PAGESELECTOR_H
+#define PAGESELECTOR_H
+
+#include <QWidget>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QLineEdit;
+class QPdfDocument;
+class QPdfPageNavigation;
+class QToolButton;
+QT_END_NAMESPACE
+
+class PageSelector : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit PageSelector(QWidget *parent = nullptr);
+
+ void setPageNavigation(QPdfPageNavigation *pageNavigation);
+
+private slots:
+ void onCurrentPageChanged(int page);
+ void pageNumberEdited();
+
+private:
+ QPdfPageNavigation *m_pageNavigation;
+
+ QLineEdit *m_pageNumberEdit;
+ QLabel *m_pageCountLabel;
+ QToolButton *m_previousPageButton;
+ QToolButton *m_nextPageButton;
+};
+
+#endif // PAGESELECTOR_H
diff --git a/examples/pdfwidgets/pdfviewer/pdfviewer.pro b/examples/pdfwidgets/pdfviewer/pdfviewer.pro
new file mode 100644
index 000000000..ad0607ea5
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/pdfviewer.pro
@@ -0,0 +1,23 @@
+TEMPLATE = app
+TARGET = pdfviewer
+QT += core gui widgets pdfwidgets
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ pageselector.cpp \
+ zoomselector.cpp
+
+HEADERS += \
+ mainwindow.h \
+ pageselector.h \
+ zoomselector.h
+
+FORMS += \
+ mainwindow.ui
+
+RESOURCES += \
+ resources.qrc
+
+target.path = $$[QT_INSTALL_EXAMPLES]/pdfwidgets/pdfviewer
+INSTALLS += target
diff --git a/examples/pdfwidgets/pdfviewer/resources.qrc b/examples/pdfwidgets/pdfviewer/resources.qrc
new file mode 100644
index 000000000..02d9655b4
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/resources.qrc
@@ -0,0 +1,12 @@
+<RCC>
+ <qresource prefix="/icons">
+ <file>images/fileopen.png</file>
+ <file>images/go-next-24.png</file>
+ <file>images/go-previous-24.png</file>
+ <file>images/zoom-in-24.png</file>
+ <file>images/zoom-in-32.png</file>
+ <file>images/zoom-out-24.png</file>
+ <file>images/zoom-out-32.png</file>
+ <file>images/busy.png</file>
+ </qresource>
+</RCC>
diff --git a/examples/pdfwidgets/pdfviewer/zoomselector.cpp b/examples/pdfwidgets/pdfviewer/zoomselector.cpp
new file mode 100644
index 000000000..0205489aa
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/zoomselector.cpp
@@ -0,0 +1,97 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "zoomselector.h"
+
+#include <QLineEdit>
+
+ZoomSelector::ZoomSelector(QWidget *parent)
+ : QComboBox(parent)
+{
+ setEditable(true);
+
+ addItem(QLatin1String("Fit Width"));
+ addItem(QLatin1String("Fit Page"));
+ addItem(QLatin1String("12%"));
+ addItem(QLatin1String("25%"));
+ addItem(QLatin1String("33%"));
+ addItem(QLatin1String("50%"));
+ addItem(QLatin1String("66%"));
+ addItem(QLatin1String("75%"));
+ addItem(QLatin1String("100%"));
+ addItem(QLatin1String("125%"));
+ addItem(QLatin1String("150%"));
+ addItem(QLatin1String("200%"));
+ addItem(QLatin1String("400%"));
+
+ connect(this, static_cast<void(QComboBox::*)(const QString &)>(&QComboBox::currentIndexChanged),
+ this, &ZoomSelector::onCurrentTextChanged);
+
+ connect(lineEdit(), &QLineEdit::editingFinished,
+ this, [this](){onCurrentTextChanged(lineEdit()->text()); });
+}
+
+void ZoomSelector::setZoomFactor(qreal zoomFactor)
+{
+ setCurrentText(QString::number(qRound(zoomFactor * 100)) + QLatin1String("%"));
+}
+
+void ZoomSelector::reset()
+{
+ setCurrentIndex(8); // 100%
+}
+
+void ZoomSelector::onCurrentTextChanged(const QString &text)
+{
+ if (text == QLatin1String("Fit Width")) {
+ emit zoomModeChanged(QPdfView::FitToWidth);
+ } else if (text == QLatin1String("Fit Page")) {
+ emit zoomModeChanged(QPdfView::FitInView);
+ } else {
+ qreal factor = 1.0;
+
+ QString withoutPercent(text);
+ withoutPercent.remove(QLatin1Char('%'));
+
+ bool ok = false;
+ const int zoomLevel = withoutPercent.toInt(&ok);
+ if (ok)
+ factor = zoomLevel / 100.0;
+
+ emit zoomModeChanged(QPdfView::CustomZoom);
+ emit zoomFactorChanged(factor);
+ }
+}
diff --git a/examples/pdfwidgets/pdfviewer/zoomselector.h b/examples/pdfwidgets/pdfviewer/zoomselector.h
new file mode 100644
index 000000000..c58d09970
--- /dev/null
+++ b/examples/pdfwidgets/pdfviewer/zoomselector.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klaralvdalens Datakonsult AB (KDAB).
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef ZOOMSELECTOR_H
+#define ZOOMSELECTOR_H
+
+#include <QComboBox>
+#include <QPdfView>
+
+class ZoomSelector : public QComboBox
+{
+ Q_OBJECT
+
+public:
+ explicit ZoomSelector(QWidget *parent = nullptr);
+
+public slots:
+ void setZoomFactor(qreal zoomFactor);
+
+ void reset();
+
+signals:
+ void zoomModeChanged(QPdfView::ZoomMode zoomMode);
+ void zoomFactorChanged(qreal zoomFactor);
+
+private slots:
+ void onCurrentTextChanged(const QString &text);
+};
+
+#endif // ZOOMSELECTOR_H
diff --git a/examples/pdfwidgets/pdfwidgets.pro b/examples/pdfwidgets/pdfwidgets.pro
new file mode 100644
index 000000000..a12dc5b86
--- /dev/null
+++ b/examples/pdfwidgets/pdfwidgets.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += pdfviewer
diff --git a/mkspecs/features/functions.prf b/mkspecs/features/functions.prf
index 512e2523b..db0b072a7 100644
--- a/mkspecs/features/functions.prf
+++ b/mkspecs/features/functions.prf
@@ -74,6 +74,7 @@ defineReplace(gnPath) {
defineReplace(gnArgs) {
linux: include($$QTWEBENGINE_ROOT/src/buildtools/config/linux.pri)
macos: include($$QTWEBENGINE_ROOT/src/buildtools/config/mac_osx.pri)
+ ios: include($$QTWEBENGINE_ROOT/src/buildtools/config/ios.pri)
win32: include($$QTWEBENGINE_ROOT/src/buildtools/config/windows.pri)
isEmpty(gn_args): error(No gn_args found please make sure you have valid configuration.)
return($$gn_args)
diff --git a/mkspecs/features/gn_generator.prf b/mkspecs/features/gn_generator.prf
index 863169c4d..6ff09d851 100644
--- a/mkspecs/features/gn_generator.prf
+++ b/mkspecs/features/gn_generator.prf
@@ -12,13 +12,18 @@ defineReplace(getTargetType) {
defineReplace(filter_flag_values) {
value_to_check = $$1
- macos:equals(value_to_check, "$(EXPORT_ARCH_ARGS)") {
+ if (macos|ios):equals(value_to_check, "$(EXPORT_ARCH_ARGS)") {
# EXPORT_ARCH_ARGS comes from qtbase/mkspecs/features/mac/default_post.prf which is a way
# to figure out the architectures to pass to the compiler at Makefile time. Because this
# variable expansion is not supported by GN, we filter it out. GN takes care of assigning
# the architecture itself.
return("")
}
+ if (ios) {
+ equals(value_to_check, "$(EXPORT_QMAKE_XARCH_LFLAGS)"): return("")
+ equals(value_to_check, "$(EXPORT_QMAKE_XARCH_CFLAGS)"): return("")
+ }
+
return($$value_to_check)
}
@@ -183,7 +188,7 @@ GN_CONTENTS += "$${TARGET_TYPE}(\"$$TARGET\") {"
}
GN_CONTENTS += " configs += [ \":$${TARGET}_config\" ]"
-GN_CONTENTS += " configs += [ \"//build/config:precompiled_headers\" ]"
+!isEmpty(GN_PRECOMPILED_HEADERS): GN_CONTENTS += " configs += [ \"//build/config:precompiled_headers\" ]"
# Source files to compile
GN_CONTENTS += " sources = ["
@@ -239,11 +244,10 @@ GN_CONTENTS += " \":generate_cpp_mocs\","
GN_CONTENTS += " ]"
GN_CONTENTS += " }"
GN_CONTENTS += "}"
-GN_CONTENTS += ""
-GN_CONTENTS += "if (!defined(core_include_dirs)) {"\
- " core_include_dirs = []"\
- "}"
!isEmpty(GN_CORE_INCLUDE_DIRS) {
+ GN_CONTENTS += " if (!defined(core_include_dirs)) {"\
+ " core_include_dirs = []"\
+ " }"
GN_CONTENTS += "core_include_dirs += ["
for (inc, GN_CORE_INCLUDE_DIRS): GN_CONTENTS += " \"$$inc\","
GN_CONTENTS += "]"
diff --git a/src/3rdparty b/src/3rdparty
-Subproject 6c9be50c2d901e66119679155fb3c7c9200448d
+Subproject 9424dc7ceeccf6e6d5edc7757edb39a7ae4983a
diff --git a/src/buildtools/config/common.pri b/src/buildtools/config/common.pri
index 97d39535c..f2b4a854e 100644
--- a/src/buildtools/config/common.pri
+++ b/src/buildtools/config/common.pri
@@ -8,6 +8,8 @@ gn_args += \
closure_compile=false \
is_component_build=false \
is_shared=true \
+ enable_debugallocation=false \
+ enable_media_remoting=false \
enable_message_center=false \
enable_nacl=false \
enable_remoting=false \
@@ -18,15 +20,15 @@ gn_args += \
enable_web_speech=false \
enable_widevine=true \
has_native_accessibility=false \
- enable_debugallocation=false \
+ optimize_webui=false \
+ safe_browsing_mode=0 \
+ strip_absolute_paths_from_debug_symbols=false \
+ toolkit_views=false \
+ treat_warnings_as_errors=false \
use_allocator_shim=false \
use_allocator=\"none\" \
use_custom_libcxx=false \
v8_use_external_startup_data=false \
- toolkit_views=false \
- treat_warnings_as_errors=false \
- safe_browsing_mode=0 \
- optimize_webui=false \
forbid_non_component_debug_builds=false
greaterThan(QMAKE_JUMBO_MERGE_LIMIT,0) {
@@ -39,7 +41,7 @@ greaterThan(QMAKE_JUMBO_MERGE_LIMIT,0) {
gn_args += jumbo_build_excluded="[\"browser\"]"
}
-qtConfig(webengine-printing-and-pdf) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-printing-and-pdf) {
gn_args += enable_basic_printing=true enable_print_preview=true
gn_args += enable_pdf=true
} else {
@@ -47,27 +49,31 @@ qtConfig(webengine-printing-and-pdf) {
gn_args += enable_pdf=false
}
-qtConfig(webengine-pepper-plugins) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-pepper-plugins) {
gn_args += enable_plugins=true
} else {
gn_args += enable_plugins=false
}
-qtConfig(webengine-spellchecker) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-spellchecker) {
gn_args += enable_spellcheck=true
} else {
gn_args += enable_spellcheck=false
}
-qtConfig(webengine-webrtc) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-webrtc) {
gn_args += enable_webrtc=true
} else {
gn_args += enable_webrtc=false audio_processing_in_audio_service_supported=false
}
-qtConfig(webengine-proprietary-codecs): gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\"
+qtConfig(build-qtwebengine-core):qtConfig(webengine-proprietary-codecs) {
+ gn_args += proprietary_codecs=true ffmpeg_branding=\"Chrome\"
+} else {
+ gn_args += proprietary_codecs=false
+}
-qtConfig(webengine-extensions) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-extensions) {
gn_args += enable_extensions=true
} else {
gn_args += enable_extensions=false
@@ -122,13 +128,7 @@ optimize_size: gn_args += optimize_for_size=true
sanitize_undefined: gn_args += is_ubsan=true is_ubsan_vptr=true
}
-qtConfig(webengine-v8-snapshot):qtConfig(webengine-v8-snapshot-support) {
- gn_args += v8_use_snapshot=true
-} else {
- gn_args += v8_use_snapshot=false
-}
-
-qtConfig(webengine-kerberos) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-kerberos) {
gn_args += use_kerberos=true
} else {
gn_args += use_kerberos=false
@@ -139,3 +139,4 @@ ccache {
}
qtConfig(force_asserts): gn_args += dcheck_always_on=true
+
diff --git a/src/buildtools/config/ios.pri b/src/buildtools/config/ios.pri
new file mode 100644
index 000000000..5dc7faf9d
--- /dev/null
+++ b/src/buildtools/config/ios.pri
@@ -0,0 +1,66 @@
+load(functions)
+
+include($$QTWEBENGINE_OUT_ROOT/src/buildtools/qtbuildtools-config.pri)
+include($$QTWEBENGINE_OUT_ROOT/src/pdf/qtpdf-config.pri)
+QT_FOR_CONFIG += buildtools-private pdf-private
+
+clang_dir = $$which($${QMAKE_CXX})
+clang_dir = $$clean_path("$$dirname(clang_dir)/../")
+
+gn_args += \
+use_qt=true \
+closure_compile=false \
+is_component_build=false \
+is_shared=true \
+is_debug=true \
+enable_message_center=false \
+enable_nacl=false \
+enable_remoting=false \
+enable_reporting=false \
+enable_resource_whitelist_generation=false \
+enable_swiftshader=false \
+enable_web_speech=false \
+has_native_accessibility=false \
+enable_debugallocation=false \
+use_allocator_shim=false \
+use_allocator=\"none\" \
+use_custom_libcxx=false \
+v8_use_external_startup_data=false \
+v8_use_snapshot=false \
+toolkit_views=false \
+treat_warnings_as_errors=false \
+safe_browsing_mode=0 \
+optimize_webui=false \
+forbid_non_component_debug_builds=false \
+clang_use_chrome_plugins=false \
+use_xcode_clang=true \
+clang_base_path=\"$${clang_dir}\" \
+ios_enable_code_signing=false \
+target_os=\"ios\" \
+ios_deployment_target=\"$${QMAKE_IOS_DEPLOYMENT_TARGET}\" \
+enable_ios_bitcode=true \
+use_jumbo_build=false
+
+device:simulator {
+ # we do fat libray
+ gn_args+= \
+ target_cpu=\"$${QMAKE_APPLE_DEVICE_ARCHS}\" \
+ use_qt_fat_lib=true \
+ arm_use_neon=false\
+ # note this adds one arch of simulator at the moment, see also additional_target_cpus
+ target_sysroot=\"$$xcodeSDKInfo(Path, $$device.sdk)\" \
+ additional_target_sysroot=[\"$$xcodeSDKInfo(Path, $$simulator.sdk)\"]
+} else {
+ simulator {
+ equals(QMAKE_APPLE_SIMULATOR_ARCHS,"x86_64") {
+ gn_args+=target_cpu=\"x64\"
+ } else {
+ gn_args+=target_cpu=\"$${QMAKE_APPLE_SIMULATOR_ARCHS}\"
+ }
+ gn_args+=target_sysroot=\"$$xcodeSDKInfo(Path, $$simulator.sdk)\"
+ }
+ device {
+ gn_args+=target_cpu=\"$${QMAKE_APPLE_DEVICE_ARCHS}\"
+ gn_args+=target_sysroot=\"$$xcodeSDKInfo(Path, $$device.sdk)\"
+ }
+}
diff --git a/src/buildtools/config/linux.pri b/src/buildtools/config/linux.pri
index ee08f81bc..2aa345c21 100644
--- a/src/buildtools/config/linux.pri
+++ b/src/buildtools/config/linux.pri
@@ -5,7 +5,7 @@ defineReplace(extractCFlag) {
return($$qtwebengine_extractCFlag($$1))
}
-QT_FOR_CONFIG += gui-private webenginecore-private
+QT_FOR_CONFIG += gui-private webenginecore-private pdf-private
gn_args += \
use_cups=false \
@@ -17,8 +17,6 @@ gn_args += \
use_sysroot=false \
enable_session_service=false \
is_cfi=false \
- strip_absolute_paths_from_debug_symbols=false \
- toolkit_views=false \
use_ozone=true \
ozone_auto_platforms=false \
ozone_platform_headless=false \
@@ -26,7 +24,7 @@ gn_args += \
ozone_platform=\"qt\" \
ozone_extra_path=\"$$QTWEBENGINE_ROOT/src/core/ozone/ozone_extra.gni\"
-qtConfig(webengine-embedded-build) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-embedded-build) {
gn_args += is_desktop_linux=false
}
@@ -92,7 +90,7 @@ contains(QT_ARCH, "arm") {
}
}
- qtConfig(webengine-arm-thumb) {
+ qtConfig(build-qtwebengine-core):qtConfig(webengine-arm-thumb) {
gn_args += arm_use_thumb=true # this adds -mthumb
} else {
gn_args += arm_use_thumb=false
@@ -158,11 +156,15 @@ host_build {
qtConfig(webengine-system-zlib) {
qtConfig(webengine-system-minizip): gn_args += use_system_zlib=true use_system_minizip=true
- qtConfig(webengine-printing-and-pdf): gn_args += pdfium_use_system_zlib=true
+ qtConfig(build-qtpdf) || qtConfig(webengine-printing-and-pdf) {
+ gn_args += pdfium_use_system_zlib=true
+ }
}
qtConfig(webengine-system-png) {
gn_args += use_system_libpng=true
- qtConfig(webengine-printing-and-pdf): gn_args += pdfium_use_system_libpng=true
+ qtConfig(build-qtpdf) || qtConfig(webengine-printing-and-pdf) {
+ gn_args += pdfium_use_system_libpng=true
+ }
}
qtConfig(webengine-system-jpeg) {
gn_args += use_system_libjpeg=true
@@ -180,19 +182,19 @@ host_build {
gn_args += use_system_harfbuzz=false
}
gn_args += use_glib=false
- qtConfig(webengine-pulseaudio) {
+ qtConfig(build-qtwebengine-core):qtConfig(webengine-pulseaudio) {
gn_args += use_pulseaudio=true
} else {
gn_args += use_pulseaudio=false
}
- qtConfig(webengine-alsa) {
+ qtConfig(build-qtwebengine-core):qtConfig(webengine-alsa) {
gn_args += use_alsa=true
} else {
gn_args += use_alsa=false
}
!packagesExist(libpci): gn_args += use_libpci=false
- qtConfig(webengine-ozone-x11) {
+ qtConfig(build-qtwebengine-core):qtConfig(webengine-ozone-x11) {
gn_args += ozone_platform_x11=true
packagesExist(xscrnsaver): gn_args += use_xscrnsaver=true
qtConfig(webengine-webrtc): gn_args += rtc_use_x11=true
diff --git a/src/buildtools/config/mac_osx.pri b/src/buildtools/config/mac_osx.pri
index 3f2fe9c0a..a7ed61214 100644
--- a/src/buildtools/config/mac_osx.pri
+++ b/src/buildtools/config/mac_osx.pri
@@ -31,7 +31,7 @@ gn_args += \
mac_sdk_min=\"$${QMAKE_MAC_SDK_VERSION}\" \
use_external_popup_menu=false
-qtConfig(webengine-spellchecker) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-spellchecker) {
qtConfig(webengine-native-spellchecker): gn_args += use_browser_spellchecker=true
else: gn_args += use_browser_spellchecker=false
} else {
diff --git a/src/buildtools/config/pdf.pri b/src/buildtools/config/pdf.pri
new file mode 100644
index 000000000..4a1cf08e0
--- /dev/null
+++ b/src/buildtools/config/pdf.pri
@@ -0,0 +1,36 @@
+include($$QTWEBENGINE_OUT_ROOT/src/pdf/qtpdf-config.pri)
+QT_FOR_CONFIG += pdf-private
+
+qtConfig(build-qtpdf) {
+ qtConfig(pdf-v8) {
+ gn_args += pdf_enable_v8=true
+ } else {
+ gn_args += pdf_enable_v8=false
+ }
+ qtConfig(pdf-xfa) {
+ gn_args += pdf_enable_xfa=true
+ } else {
+ gn_args += pdf_enable_xfa=false
+ }
+ qtConfig(pdf-xfa-bmp) {
+ gn_args += pdf_enable_xfa_bmp=true
+ } else {
+ gn_args += pdf_enable_xfa_bmp=false
+ }
+ qtConfig(pdf-xfa-gif) {
+ gn_args += pdf_enable_xfa_gif=true
+ } else {
+ gn_args += pdf_enable_xfa_gif=false
+ }
+ qtConfig(pdf-xfa-png) {
+ gn_args += pdf_enable_xfa_png=true
+ } else {
+ gn_args += pdf_enable_xfa_png=false
+ }
+ qtConfig(pdf-xfa-tiff) {
+ gn_args += pdf_enable_xfa_tiff=true
+ } else {
+ gn_args += pdf_enable_xfa_tiff=false
+ }
+}
+
diff --git a/src/buildtools/config/support.pri b/src/buildtools/config/support.pri
index 5bdd808d4..8077b12ff 100644
--- a/src/buildtools/config/support.pri
+++ b/src/buildtools/config/support.pri
@@ -6,11 +6,6 @@ defineTest(qtwebengine_skipBuild) {
defineReplace(qtwebengine_checkError) {
- static {
- qtwebengine_skipBuild("Static builds of QtWebEngine are not supported.")
- return(false)
- }
-
!qtHaveModule(gui) {
qtwebengine_skipBuild("QtWebEngine requires QtGui.")
return(false)
@@ -67,7 +62,8 @@ defineReplace(qtwebengine_checkError) {
}
linux:!qtwebengine_checkErrorForLinux():return(false)
- win:!qtwebengine_checkErrorForWindows():return(false)
+ win32:!qtwebengine_checkErrorForWindows():return(false)
+ macos:!qtwebengine_checkErrorForMacOS():return(false)
sanitizer: !qtConfig(webengine-sanitizer) {
qtwebengine_skipBuild("Chosen sanitizer configuration is not supported for QtWebEngine. Check config.log for details or use -feature-webengine-sanitizer to force build with the chosen sanitizer configuration.")
@@ -77,8 +73,20 @@ defineReplace(qtwebengine_checkError) {
return(true)
}
+defineTest(qtwebengine_checkErrorFoMacOS) {
+ static {
+ qtwebengine_skipBuild("Static builds of QtWebEngine are not supported.")
+ return(false)
+ }
+}
+
defineTest(qtwebengine_checkErrorForLinux) {
+ static {
+ qtwebengine_skipBuild("Static builds of QtWebEngine are not supported.")
+ return(false)
+ }
+
!qtConfig(pkg-config) {
qtwebengine_skipBuild("A pkg-config support is required to build QtWebEngine.")
return(false)
@@ -114,6 +122,12 @@ defineTest(qtwebengine_checkErrorForLinux) {
}
defineTest(qtwebengine_checkErrorForWindows) {
+
+ static {
+ qtwebengine_skipBuild("Static builds of QtWebEngine are not supported.")
+ return(false)
+ }
+
!qtConfig(webengine-win-compiler64) {
qtwebengine_skipBuild("64-bit cross-building or native toolchain required to build QtWebEngine could not be found.")
return(false)
diff --git a/src/buildtools/config/windows.pri b/src/buildtools/config/windows.pri
index 5d7b7e1f2..a910e3e31 100644
--- a/src/buildtools/config/windows.pri
+++ b/src/buildtools/config/windows.pri
@@ -56,12 +56,17 @@ defineTest(usingMSVC32BitCrossCompiler) {
}
CL_DIR = $$system_path($$CL_DIR)
CL_DIR = $$split(CL_DIR, \\)
- CL_PLATFORM = $$last(CL_DIR)
+ CL_PLATFORM = $$take_last(CL_DIR)
equals(CL_PLATFORM, amd64_x86): return(true)
+ equals(CL_PLATFORM, x86)|equals(CL_PLATFORM, x64) {
+ CL_PLATFORM = $$take_last(CL_DIR)
+ equals(CL_PLATFORM, HostX64): return(true)
+ }
return(false)
}
msvc:contains(QT_ARCH, "i386"):!usingMSVC32BitCrossCompiler() {
+ warning(Full debug info is disabled for chromium due to 32bit compiler)
# The 32 bit MSVC linker runs out of memory if we do not remove all debug information.
force_debug_info: gn_args -= symbol_level=1
gn_args *= symbol_level=0
@@ -89,7 +94,7 @@ msvc {
error("Qt WebEngine for Windows can only be built with a Microsoft Visual Studio C++ compatible compiler")
}
-qtConfig(webengine-spellchecker) {
+qtConfig(build-qtwebengine-core):qtConfig(webengine-spellchecker) {
qtConfig(webengine-native-spellchecker): gn_args += use_browser_spellchecker=true
else: gn_args += use_browser_spellchecker=false
} else {
diff --git a/src/buildtools/configure.json b/src/buildtools/configure.json
index f04fdae81..c2531a744 100644
--- a/src/buildtools/configure.json
+++ b/src/buildtools/configure.json
@@ -9,6 +9,7 @@
"commandline": {
"options": {
"build-qtwebengine-core": "boolean",
+ "build-qtpdf": "boolean",
"webengine-jumbo-build": { "type": "optionalString", "name": "merge_limit"}
}
},
@@ -263,10 +264,11 @@
"main": [
"vpx_codec_cx_pkt pkt;",
"pkt.data.frame.width[0] = 0u;",
- "pkt.data.frame.height[0] = 0u;"
+ "pkt.data.frame.height[0] = 0u;",
+ "auto a = CONSTRAINED_FROM_ABOVE_DROP;"
]
},
- "headers": "vpx/vpx_encoder.h",
+ "headers": [ "vpx/vpx_encoder.h", "vpx/vp8cx.h" ],
"sources": [
{ "type": "pkgConfig", "args": "vpx" },
"-lvpx"
@@ -386,6 +388,23 @@
&& !config.static
&& (!config.linux || features.pkg-config)
&& (!features.xcb || features.webengine-ozone-x11)
+ && (!config.win32 || features.webengine-winversion)
+ && !config.ios",
+ "output": [ "privateFeature" ]
+ },
+ "webengine-qtpdf-support": {
+ "label": "Support Qt Pdf",
+ "condition": "module.gui
+ && features.webengine-python2
+ && features.webengine-gperf
+ && features.webengine-bison
+ && features.webengine-flex
+ && features.webengine-submodule
+ && features.webengine-nowhitespace
+ && features.webengine-arch-support
+ && !features.webengine-no-platform-support
+ && (!config.static || config.ios)
+ && (!config.linux || features.pkg-config)
&& (!config.win32 || features.webengine-winversion)",
"output": [ "privateFeature" ]
},
@@ -681,7 +700,8 @@
"report": [
{
"type": "skipBuildWarning",
- "condition": "!features.webengine-core-support && (features.build-qtwebengine-core || features.build-qtpdf)",
+ "condition": "(!features.webengine-core-support && features.build-qtwebengine-core) ||
+ (!features.webengine-qtpdf-support && features.build-qtpdf)",
"message": "qtwebengine_confCheckError"
},
{
@@ -691,7 +711,7 @@
},
{
"type": "note",
- "condition": "features.webengine-core-support && !features.build-qtpdf",
+ "condition": "features.webengine-qtpdf-support && !features.build-qtpdf",
"message": "QtPdf build is disabled by user."
},
{
@@ -701,8 +721,13 @@
},
{
"type": "warning",
- "condition": "!features.webengine-core-support && features.build-qtpdf",
+ "condition": "!features.webengine-qtpdf-support && features.build-qtpdf",
"message": "QtPdf will not be built."
+ },
+ {
+ "type": "warning",
+ "condition": "config.ios && config.simulator && config.device && features.build-qtpdf",
+ "message": "Building fat libray with device and simulator architectures will disable NEON."
}
],
"summary": [
@@ -711,14 +736,14 @@
"entries": [
"webengine-system-ninja",
"webengine-system-gn",
- {
+ {
"message": "Jumbo Build Merge Limit",
"type": "jumboBuild"
},
"webengine-developer-build",
{
"section": "QtWebEngine required system libraries",
- "condition": "config.unix && !config.macos",
+ "condition": "config.unix && !config.macos && !config.ios",
"entries": [
"webengine-system-fontconfig",
"webengine-system-dbus",
diff --git a/src/core/accessibility_tree_formatter_qt.cpp b/src/core/accessibility_tree_formatter_qt.cpp
index 3520087ae..334759abb 100644
--- a/src/core/accessibility_tree_formatter_qt.cpp
+++ b/src/core/accessibility_tree_formatter_qt.cpp
@@ -59,7 +59,7 @@ public:
~AccessibilityTreeFormatterQt() override;
private:
- const base::FilePath::StringType GetExpectedFileSuffix() override;
+ base::FilePath::StringType GetExpectedFileSuffix() override;
const std::string GetAllowEmptyString() override;
const std::string GetAllowString() override;
const std::string GetDenyString() override;
@@ -179,7 +179,7 @@ base::string16 AccessibilityTreeFormatterQt::ProcessTreeForOutput(const base::Di
return line + base::ASCIIToUTF16("\n");
}
-const base::FilePath::StringType AccessibilityTreeFormatterQt::GetExpectedFileSuffix()
+base::FilePath::StringType AccessibilityTreeFormatterQt::GetExpectedFileSuffix()
{
return FILE_PATH_LITERAL("-expected-qt.txt");
}
diff --git a/src/core/api/core_api.pro b/src/core/api/core_api.pro
index 5e8b8387e..6b4291cb7 100644
--- a/src/core/api/core_api.pro
+++ b/src/core/api/core_api.pro
@@ -67,11 +67,13 @@ SOURCES = \
### Qt6 Remove this workaround
unix:!isEmpty(QMAKE_LFLAGS_VERSION_SCRIPT):!static {
- CONFIG -= warning_clean
SOURCES += qtbug-60565.cpp \
qtbug-61521.cpp
}
+# Chromium headers included are not remotely clean
+CONFIG -= warning_clean
+
msvc {
# Create a list of object files that can be used as response file for the linker.
# This is done to simulate -whole-archive on MSVC.
diff --git a/src/core/api/qwebengineurlrequestinfo.cpp b/src/core/api/qwebengineurlrequestinfo.cpp
index e44410099..3816f08ca 100644
--- a/src/core/api/qwebengineurlrequestinfo.cpp
+++ b/src/core/api/qwebengineurlrequestinfo.cpp
@@ -145,11 +145,25 @@ QWebEngineUrlRequestInfoPrivate::QWebEngineUrlRequestInfoPrivate(QWebEngineUrlRe
/*!
\internal
*/
+QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo() {}
+
+/*!
+ \internal
+*/
QWebEngineUrlRequestInfo::QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfo &&p) : d_ptr(p.d_ptr.take()) {}
/*!
\internal
*/
+QWebEngineUrlRequestInfo &QWebEngineUrlRequestInfo::operator=(QWebEngineUrlRequestInfo &&p)
+{
+ d_ptr.reset(p.d_ptr.take());
+ return *this;
+}
+
+/*!
+ \internal
+*/
QWebEngineUrlRequestInfo::~QWebEngineUrlRequestInfo() {}
diff --git a/src/core/api/qwebengineurlrequestinfo.h b/src/core/api/qwebengineurlrequestinfo.h
index 75b6e3a81..21e44d2f1 100644
--- a/src/core/api/qwebengineurlrequestinfo.h
+++ b/src/core/api/qwebengineurlrequestinfo.h
@@ -46,6 +46,7 @@
#include <QtCore/qurl.h>
namespace QtWebEngineCore {
+class InterceptedRequest;
class NetworkDelegateQt;
class URLRequestNotification;
} // namespace QtWebEngineCore
@@ -110,13 +111,16 @@ public:
private:
friend class QtWebEngineCore::NetworkDelegateQt;
friend class QtWebEngineCore::URLRequestNotification;
+ friend class QtWebEngineCore::InterceptedRequest;
Q_DISABLE_COPY(QWebEngineUrlRequestInfo)
Q_DECLARE_PRIVATE(QWebEngineUrlRequestInfo)
void resetChanged();
+ QWebEngineUrlRequestInfo();
QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfoPrivate *p);
QWebEngineUrlRequestInfo(QWebEngineUrlRequestInfo &&p);
+ QWebEngineUrlRequestInfo &operator=(QWebEngineUrlRequestInfo &&p);
~QWebEngineUrlRequestInfo();
QScopedPointer<QWebEngineUrlRequestInfoPrivate> d_ptr;
};
diff --git a/src/core/authentication_dialog_controller.cpp b/src/core/authentication_dialog_controller.cpp
index 23dd62979..e37ffab44 100644
--- a/src/core/authentication_dialog_controller.cpp
+++ b/src/core/authentication_dialog_controller.cpp
@@ -53,11 +53,9 @@ AuthenticationDialogControllerPrivate::AuthenticationDialogControllerPrivate(bas
void AuthenticationDialogControllerPrivate::dialogFinished(bool accepted, const QString &user, const QString &password)
{
- base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&LoginDelegateQt::sendAuthToRequester,
- loginDelegate,
- accepted, user, password));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(&LoginDelegateQt::sendAuthToRequester,
+ loginDelegate, accepted, user, password));
}
AuthenticationDialogController::AuthenticationDialogController(AuthenticationDialogControllerPrivate *dd)
diff --git a/src/core/browser_accessibility_qt.cpp b/src/core/browser_accessibility_qt.cpp
index 816a46041..d816678e3 100644
--- a/src/core/browser_accessibility_qt.cpp
+++ b/src/core/browser_accessibility_qt.cpp
@@ -225,8 +225,15 @@ QAccessible::Role BrowserAccessibilityQt::role() const
return QAccessible::AlertMessage;
case ax::mojom::Role::kAnchor:
return QAccessible::Link;
- case ax::mojom::Role::kAnnotation:
- return QAccessible::StaticText;
+
+ // REMINDER: annotation roles are removed from Chromium 80: https://chromium-review.googlesource.com/c/chromium/src/+/1907074
+ case ax::mojom::Role::kAnnotationAttribution:
+ case ax::mojom::Role::kAnnotationCommentary:
+ case ax::mojom::Role::kAnnotationPresence:
+ case ax::mojom::Role::kAnnotationRevision:
+ case ax::mojom::Role::kAnnotationSuggestion:
+ return QAccessible::Section;
+
case ax::mojom::Role::kApplication:
return QAccessible::Document; // returning Application here makes Qt return the top level app object
case ax::mojom::Role::kArticle:
@@ -282,17 +289,17 @@ QAccessible::Role BrowserAccessibilityQt::role() const
case ax::mojom::Role::kDetails:
return QAccessible::Grouping;
case ax::mojom::Role::kDesktop:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::Pane;
case ax::mojom::Role::kDialog:
return QAccessible::Dialog;
case ax::mojom::Role::kDirectory:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::List;
case ax::mojom::Role::kDisclosureTriangle:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::Button;
case ax::mojom::Role::kGenericContainer:
return QAccessible::Section;
case ax::mojom::Role::kDocCover:
- return QAccessible::Graphic;
+ return QAccessible::Graphic;
case ax::mojom::Role::kDocBackLink:
case ax::mojom::Role::kDocBiblioRef:
case ax::mojom::Role::kDocGlossRef:
@@ -331,14 +338,16 @@ QAccessible::Role BrowserAccessibilityQt::role() const
case ax::mojom::Role::kDocPrologue:
case ax::mojom::Role::kDocPullquote:
case ax::mojom::Role::kDocQna:
+ return QAccessible::Section;
case ax::mojom::Role::kDocSubtitle:
+ return QAccessible::Heading;
case ax::mojom::Role::kDocTip:
case ax::mojom::Role::kDocToc:
return QAccessible::Section;
case ax::mojom::Role::kDocument:
return QAccessible::Document;
case ax::mojom::Role::kEmbeddedObject:
- return QAccessible::Grouping; // FIXME
+ return QAccessible::Grouping;
case ax::mojom::Role::kFeed:
return QAccessible::Section;
case ax::mojom::Role::kFigcaption:
@@ -347,6 +356,8 @@ QAccessible::Role BrowserAccessibilityQt::role() const
return QAccessible::Section;
case ax::mojom::Role::kFooter:
return QAccessible::Footer;
+ case ax::mojom::Role::kFooterAsNonLandmark:
+ return QAccessible::Section;
case ax::mojom::Role::kForm:
return QAccessible::Form;
case ax::mojom::Role::kGraphicsDocument:
@@ -359,20 +370,23 @@ QAccessible::Role BrowserAccessibilityQt::role() const
return QAccessible::Table;
case ax::mojom::Role::kGroup:
return QAccessible::Grouping;
+ case ax::mojom::Role::kHeader:
+ case ax::mojom::Role::kHeaderAsNonLandmark:
+ return QAccessible::Section;
case ax::mojom::Role::kHeading:
return QAccessible::Heading;
case ax::mojom::Role::kIframe:
- return QAccessible::Grouping;
+ return QAccessible::WebDocument;
case ax::mojom::Role::kIframePresentational:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::Grouping;
case ax::mojom::Role::kIgnored:
return QAccessible::NoRole;
case ax::mojom::Role::kImage:
return QAccessible::Graphic;
case ax::mojom::Role::kImageMap:
- return QAccessible::Graphic;
+ return QAccessible::Document;
case ax::mojom::Role::kInlineTextBox:
- return QAccessible::EditableText;
+ return QAccessible::StaticText;
case ax::mojom::Role::kInputTime:
return QAccessible::SpinBox;
case ax::mojom::Role::kKeyboard:
@@ -383,8 +397,7 @@ QAccessible::Role BrowserAccessibilityQt::role() const
case ax::mojom::Role::kLayoutTableCell:
case ax::mojom::Role::kLayoutTableColumn:
case ax::mojom::Role::kLayoutTableRow:
- // No role description.
- return QAccessible::NoRole;
+ return QAccessible::Section;
case ax::mojom::Role::kLegend:
return QAccessible::StaticText;
case ax::mojom::Role::kLineBreak:
@@ -459,18 +472,21 @@ QAccessible::Role BrowserAccessibilityQt::role() const
return QAccessible::RowHeader;
case ax::mojom::Role::kRuby:
return QAccessible::StaticText;
+ case ax::mojom::Role::kRubyAnnotation:
+ return QAccessible::StaticText;
case ax::mojom::Role::kScrollBar:
return QAccessible::ScrollBar;
case ax::mojom::Role::kScrollView:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::Pane;
case ax::mojom::Role::kSearch:
return QAccessible::Section;
case ax::mojom::Role::kSearchBox:
return QAccessible::EditableText;
+ case ax::mojom::Role::kSection:
+ return QAccessible::Section;
case ax::mojom::Role::kSlider:
- return QAccessible::Slider;
case ax::mojom::Role::kSliderThumb:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::Slider;
case ax::mojom::Role::kSpinButton:
return QAccessible::SpinBox;
case ax::mojom::Role::kSplitter:
@@ -501,7 +517,7 @@ QAccessible::Role BrowserAccessibilityQt::role() const
case ax::mojom::Role::kTimer:
return QAccessible::Clock;
case ax::mojom::Role::kTitleBar:
- return QAccessible::NoRole; // FIXME
+ return QAccessible::Document;
case ax::mojom::Role::kToggleButton:
return QAccessible::Button;
case ax::mojom::Role::kToolbar:
diff --git a/src/core/browser_main_parts_qt.cpp b/src/core/browser_main_parts_qt.cpp
index 3e9af8167..925c18664 100644
--- a/src/core/browser_main_parts_qt.cpp
+++ b/src/core/browser_main_parts_qt.cpp
@@ -61,12 +61,10 @@
#include "extensions/extension_system_factory_qt.h"
#include "common/extensions/extensions_client_qt.h"
#endif //BUILDFLAG(ENABLE_EXTENSIONS)
-#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
#include "ui/display/screen.h"
-#include "service/service_qt.h"
#include "web_engine_context.h"
#include <QtGui/qtgui-config.h>
@@ -281,8 +279,6 @@ int BrowserMainPartsQt::PreCreateThreads()
void BrowserMainPartsQt::PostCreateThreads()
{
- ServiceQt::GetInstance()->InitConnector();
- content::GetSystemConnector()->WarmService(service_manager::ServiceFilter::ByName("qtwebengine"));
}
} // namespace QtWebEngineCore
diff --git a/src/core/certificate_error_controller.h b/src/core/certificate_error_controller.h
index d7e057adf..7c7db37ef 100644
--- a/src/core/certificate_error_controller.h
+++ b/src/core/certificate_error_controller.h
@@ -85,8 +85,7 @@ public:
CertificateValidityTooLong = -213,
CertificateTransparencyRequired = -214,
CertificateSymantecLegacy = -215,
-
- CertificateErrorEnd = -216 // not an error, just an enum boundary
+ CertificateErrorEnd = -217 // not an error, just an enum boundary
};
CertificateError error() const;
diff --git a/src/core/chromium_overrides.cpp b/src/core/chromium_overrides.cpp
index 9d3e3f08a..01937d3e7 100644
--- a/src/core/chromium_overrides.cpp
+++ b/src/core/chromium_overrides.cpp
@@ -170,26 +170,26 @@ bool GrabViewSnapshot(gfx::NativeView view,
void GrabWindowSnapshotAndScaleAsync(gfx::NativeWindow window,
const gfx::Rect& source_rect,
const gfx::Size& target_size,
- const GrabWindowSnapshotAsyncCallback& callback)
+ GrabWindowSnapshotAsyncCallback callback)
{
NOTIMPLEMENTED();
- callback.Run(gfx::Image());
+ std::move(callback).Run(gfx::Image());
}
void GrabWindowSnapshotAsync(gfx::NativeWindow window,
const gfx::Rect& source_rect,
- const GrabWindowSnapshotAsyncCallback& callback)
+ GrabWindowSnapshotAsyncCallback callback)
{
NOTIMPLEMENTED();
- callback.Run(gfx::Image());
+ std::move(callback).Run(gfx::Image());
}
void GrabViewSnapshotAsync(gfx::NativeView view,
const gfx::Rect& source_rect,
- const GrabWindowSnapshotAsyncCallback& callback)
+ GrabWindowSnapshotAsyncCallback callback)
{
NOTIMPLEMENTED();
- callback.Run(gfx::Image());
+ std::move(callback).Run(gfx::Image());
}
} // namespace ui
diff --git a/src/core/clipboard_qt.cpp b/src/core/clipboard_qt.cpp
index 70e0a2376..ef7a05299 100644
--- a/src/core/clipboard_qt.cpp
+++ b/src/core/clipboard_qt.cpp
@@ -105,30 +105,37 @@ Clipboard *Clipboard::Create()
namespace QtWebEngineCore {
-void ClipboardQt::WriteObjects(ui::ClipboardType type, const ObjectMap &objects)
+void ClipboardQt::WritePortableRepresentations(ui::ClipboardBuffer type, const ObjectMap &objects)
{
DCHECK(CalledOnValidThread());
- DCHECK(IsSupportedClipboardType(type));
+ DCHECK(IsSupportedClipboardBuffer(type));
- for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end(); ++iter)
- DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
+ for (const auto &object : objects)
+ DispatchPortableRepresentation(object.first, object.second);
// Commit the accumulated data.
if (uncommittedData)
QGuiApplication::clipboard()->setMimeData(uncommittedData.take(),
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard
- : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard
+ : QClipboard::Selection);
- if (type == ui::ClipboardType::kCopyPaste && IsSupportedClipboardType(ui::ClipboardType::kSelection)) {
- ObjectMap::const_iterator text_iter = objects.find(CBF_TEXT);
+ if (type == ui::ClipboardBuffer::kCopyPaste && IsSupportedClipboardBuffer(ui::ClipboardBuffer::kSelection)) {
+ ObjectMap::const_iterator text_iter = objects.find(PortableFormat::kText);
if (text_iter != objects.end()) {
// Copy text and SourceTag to the selection clipboard.
- ObjectMap::const_iterator next_iter = text_iter;
- WriteObjects(ui::ClipboardType::kSelection, ObjectMap(text_iter, ++next_iter, base::KEEP_FIRST_OF_DUPES));
+ WritePortableRepresentations(ui::ClipboardBuffer::kSelection,
+ ObjectMap(text_iter, text_iter + 1));
}
}
}
+void ClipboardQt::WritePlatformRepresentations(ui::ClipboardBuffer buffer, std::vector<ui::Clipboard::PlatformRepresentation> platform_representations)
+{
+ DCHECK(CalledOnValidThread());
+ DCHECK(IsSupportedClipboardBuffer(buffer));
+ DispatchPlatformRepresentations(std::move(platform_representations));
+}
+
void ClipboardQt::WriteText(const char *text_data, size_t text_len)
{
getUncommittedData()->setText(QString::fromUtf8(text_data, text_len));
@@ -173,20 +180,20 @@ void ClipboardQt::WriteData(const ui::ClipboardFormatType &format, const char *d
getUncommittedData()->setData(QString::fromStdString(format.ToString()), QByteArray(data_data, data_len));
}
-bool ClipboardQt::IsFormatAvailable(const ui::ClipboardFormatType &format, ui::ClipboardType type) const
+bool ClipboardQt::IsFormatAvailable(const ui::ClipboardFormatType &format, ui::ClipboardBuffer type) const
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
return mimeData && mimeData->hasFormat(QString::fromStdString(format.ToString()));
}
-void ClipboardQt::Clear(ui::ClipboardType type)
+void ClipboardQt::Clear(ui::ClipboardBuffer type)
{
- QGuiApplication::clipboard()->clear(type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard
+ QGuiApplication::clipboard()->clear(type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard
: QClipboard::Selection);
}
-void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16> *types,
+void ClipboardQt::ReadAvailableTypes(ui::ClipboardBuffer type, std::vector<base::string16> *types,
bool *contains_filenames) const
{
if (!types || !contains_filenames) {
@@ -196,7 +203,7 @@ void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::s
types->clear();
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (!mimeData)
return;
if (mimeData->hasImage() && !mimeData->formats().contains(QStringLiteral("image/png")))
@@ -210,23 +217,23 @@ void ClipboardQt::ReadAvailableTypes(ui::ClipboardType type, std::vector<base::s
ui::ReadCustomDataTypes(customData.constData(), customData.size(), types);
}
-void ClipboardQt::ReadText(ui::ClipboardType type, base::string16 *result) const
+void ClipboardQt::ReadText(ui::ClipboardBuffer type, base::string16 *result) const
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (mimeData)
*result = toString16(mimeData->text());
}
-void ClipboardQt::ReadAsciiText(ui::ClipboardType type, std::string *result) const
+void ClipboardQt::ReadAsciiText(ui::ClipboardBuffer type, std::string *result) const
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (mimeData)
*result = mimeData->text().toStdString();
}
-void ClipboardQt::ReadHTML(ui::ClipboardType type, base::string16 *markup, std::string *src_url,
+void ClipboardQt::ReadHTML(ui::ClipboardBuffer type, base::string16 *markup, std::string *src_url,
uint32_t *fragment_start, uint32_t *fragment_end) const
{
markup->clear();
@@ -236,27 +243,27 @@ void ClipboardQt::ReadHTML(ui::ClipboardType type, base::string16 *markup, std::
*fragment_end = 0;
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (!mimeData)
return;
*markup = toString16(mimeData->html());
*fragment_end = static_cast<uint32_t>(markup->length());
}
-void ClipboardQt::ReadRTF(ui::ClipboardType type, std::string *result) const
+void ClipboardQt::ReadRTF(ui::ClipboardBuffer type, std::string *result) const
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (!mimeData)
return;
const QByteArray byteArray = mimeData->data(QString::fromLatin1(ui::kMimeTypeRTF));
*result = std::string(byteArray.constData(), byteArray.length());
}
-SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const
+SkBitmap ClipboardQt::ReadImage(ui::ClipboardBuffer type) const
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (!mimeData)
return SkBitmap();
QImage image = qvariant_cast<QImage>(mimeData->imageData());
@@ -279,10 +286,10 @@ SkBitmap ClipboardQt::ReadImage(ui::ClipboardType type) const
return bitmap;
}
-void ClipboardQt::ReadCustomData(ui::ClipboardType clipboard_type, const base::string16 &type, base::string16 *result) const
+void ClipboardQt::ReadCustomData(ui::ClipboardBuffer clipboard_type, const base::string16 &type, base::string16 *result) const
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData(
- clipboard_type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
+ clipboard_type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard : QClipboard::Selection);
if (!mimeData)
return;
const QByteArray customData = mimeData->data(QString::fromLatin1(ui::kMimeTypeWebCustomData));
@@ -303,10 +310,10 @@ void ClipboardQt::ReadData(const ui::ClipboardFormatType &format, std::string *r
*result = std::string(byteArray.constData(), byteArray.length());
}
-uint64_t ClipboardQt::GetSequenceNumber(ui::ClipboardType type) const
+uint64_t ClipboardQt::GetSequenceNumber(ui::ClipboardBuffer type) const
{
- return clipboardChangeObserver()->getSequenceNumber(type == ui::ClipboardType::kCopyPaste ? QClipboard::Clipboard
- : QClipboard::Selection);
+ return clipboardChangeObserver()->getSequenceNumber(type == ui::ClipboardBuffer::kCopyPaste ? QClipboard::Clipboard
+ : QClipboard::Selection);
}
} // namespace QtWebEngineCore
diff --git a/src/core/clipboard_qt.h b/src/core/clipboard_qt.h
index 7884da167..6d86e8f6c 100644
--- a/src/core/clipboard_qt.h
+++ b/src/core/clipboard_qt.h
@@ -46,25 +46,27 @@ namespace QtWebEngineCore {
class ClipboardQt : public ui::Clipboard {
public:
- uint64_t GetSequenceNumber(ui::ClipboardType type) const override;
- bool IsFormatAvailable(const ui::ClipboardFormatType &format, ui::ClipboardType type) const override;
- void Clear(ui::ClipboardType type) override;
- void ReadAvailableTypes(ui::ClipboardType type, std::vector<base::string16> *types,
+ uint64_t GetSequenceNumber(ui::ClipboardBuffer type) const override;
+ bool IsFormatAvailable(const ui::ClipboardFormatType &format, ui::ClipboardBuffer type) const override;
+ void Clear(ui::ClipboardBuffer type) override;
+ void ReadAvailableTypes(ui::ClipboardBuffer type, std::vector<base::string16> *types,
bool *contains_filenames) const override;
- void ReadText(ui::ClipboardType type, base::string16 *result) const override;
- void ReadAsciiText(ui::ClipboardType type, std::string *result) const override;
- void ReadHTML(ui::ClipboardType type, base::string16 *markup, std::string *src_url, uint32_t *fragment_start,
+ void ReadText(ui::ClipboardBuffer type, base::string16 *result) const override;
+ void ReadAsciiText(ui::ClipboardBuffer type, std::string *result) const override;
+ void ReadHTML(ui::ClipboardBuffer type, base::string16 *markup, std::string *src_url, uint32_t *fragment_start,
uint32_t *fragment_end) const override;
- void ReadRTF(ui::ClipboardType type, std::string *result) const override;
- SkBitmap ReadImage(ui::ClipboardType type) const override;
- void ReadCustomData(ui::ClipboardType clipboard_type, const base::string16 &type, base::string16 *result) const override;
+ void ReadRTF(ui::ClipboardBuffer type, std::string *result) const override;
+ SkBitmap ReadImage(ui::ClipboardBuffer type) const override;
+ void ReadCustomData(ui::ClipboardBuffer clipboard_type, const base::string16 &type, base::string16 *result) const override;
void ReadBookmark(base::string16 *title, std::string *url) const override;
void ReadData(const ui::ClipboardFormatType &format, std::string *result) const override;
void OnPreShutdown() override {}
protected:
- void WriteObjects(ui::ClipboardType type, const ObjectMap &objects) override;
+ void WritePortableRepresentations(ui::ClipboardBuffer type, const ObjectMap &objects) override;
+ void WritePlatformRepresentations(ui::ClipboardBuffer type,
+ std::vector<ui::Clipboard::PlatformRepresentation> platform_representations) 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;
diff --git a/src/core/command_line_pref_store_qt.cpp b/src/core/command_line_pref_store_qt.cpp
deleted file mode 100644
index 5c5c82e1a..000000000
--- a/src/core/command_line_pref_store_qt.cpp
+++ /dev/null
@@ -1,90 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// Copyright (c) 2012 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 file.
-
-#include "command_line_pref_store_qt.h"
-
-#include "chrome/common/chrome_switches.h"
-#include "components/proxy_config/proxy_config_dictionary.h"
-#include "components/proxy_config/proxy_config_pref_names.h"
-#include "content/public/common/content_switches.h"
-#include <QDebug>
-
-CommandLinePrefStoreQt::CommandLinePrefStoreQt(const base::CommandLine *commandLine)
- : CommandLinePrefStore(commandLine)
-{
-
- if (commandLine->HasSwitch(switches::kNoProxyServer)) {
- SetValue(proxy_config::prefs::kProxy,
- std::make_unique<base::Value>(ProxyConfigDictionary::CreateDirect()),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- } else if (commandLine->HasSwitch(switches::kProxyPacUrl)) {
- std::string pac_script_url =
- commandLine->GetSwitchValueASCII(switches::kProxyPacUrl);
- SetValue(proxy_config::prefs::kProxy,
- std::make_unique<base::Value>(ProxyConfigDictionary::CreatePacScript(
- pac_script_url, false)),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- } else if (commandLine->HasSwitch(switches::kProxyAutoDetect)) {
- SetValue(proxy_config::prefs::kProxy,
- std::make_unique<base::Value>(
- ProxyConfigDictionary::CreateAutoDetect()),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- } else if (commandLine->HasSwitch(switches::kProxyServer)) {
- std::string proxy_server =
- commandLine->GetSwitchValueASCII(switches::kProxyServer);
- std::string bypass_list =
- commandLine->GetSwitchValueASCII(switches::kProxyBypassList);
- SetValue(
- proxy_config::prefs::kProxy,
- std::make_unique<base::Value>(ProxyConfigDictionary::CreateFixedServers(
- proxy_server, bypass_list)),
- WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
- }
-
- if (commandLine->HasSwitch(switches::kNoProxyServer) && (commandLine->HasSwitch(switches::kProxyAutoDetect) || commandLine->HasSwitch(switches::kProxyServer) || commandLine->HasSwitch(switches::kProxyPacUrl) || commandLine->HasSwitch(switches::kProxyBypassList))) {
- qWarning("Additional command-line proxy switches specified when --%s was also specified",
- qPrintable(switches::kNoProxyServer));
- }
-}
-
-CommandLinePrefStoreQt::~CommandLinePrefStoreQt() = default;
diff --git a/src/core/command_line_pref_store_qt.h b/src/core/command_line_pref_store_qt.h
deleted file mode 100644
index a509f8ca9..000000000
--- a/src/core/command_line_pref_store_qt.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef COMMAND_LINE_PREF_STORE_QT_H
-#define COMMAND_LINE_PREF_STORE_QT_H
-
-#include "base/command_line.h"
-#include "components/prefs/command_line_pref_store.h"
-
-class CommandLinePrefStoreQt : public CommandLinePrefStore
-{
-public:
- explicit CommandLinePrefStoreQt(const base::CommandLine *commandLine);
-
-protected:
- ~CommandLinePrefStoreQt() override;
- DISALLOW_COPY_AND_ASSIGN(CommandLinePrefStoreQt);
-};
-
-#endif // COMMAND_LINE_PREF_STORE_QT_H
diff --git a/src/core/compositor/compositor.cpp b/src/core/compositor/compositor.cpp
index 1578e431e..82a9f7ee4 100644
--- a/src/core/compositor/compositor.cpp
+++ b/src/core/compositor/compositor.cpp
@@ -46,7 +46,7 @@
#include "components/viz/common/resources/returned_resource.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
-#include "services/viz/public/interfaces/compositing/compositor_frame_sink.mojom.h"
+#include "services/viz/privileged/mojom/compositing/frame_sink_manager.mojom.h"
namespace QtWebEngineCore {
@@ -56,7 +56,7 @@ Compositor::Compositor(content::RenderWidgetHost *host)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- m_taskRunner = base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE});
+ m_taskRunner = base::CreateSingleThreadTaskRunner({content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE});
m_beginFrameSource =
std::make_unique<viz::DelayBasedBeginFrameSource>(
std::make_unique<viz::DelayBasedTimeSource>(m_taskRunner.get()),
@@ -127,8 +127,7 @@ QSGNode *Compositor::updatePaintNode(QSGNode *oldNode, RenderWidgetHostViewQtDel
}
m_updatePaintNodeShouldCommit = false;
- gfx::PresentationFeedback dummyFeedback(base::TimeTicks::Now(), base::TimeDelta(), gfx::PresentationFeedback::Flags::kVSync);
- m_presentations.emplace(m_committedFrame.metadata.frame_token, viz::FrameTimingDetails{dummyFeedback});
+ m_presentations.emplace(m_committedFrame.metadata.frame_token, viz::FrameTimingDetails{base::TimeTicks::Now()});
m_resourceTracker->commitResources();
frameNode->commit(m_pendingFrame, m_committedFrame, m_resourceTracker.get(), viewDelegate);
@@ -160,8 +159,7 @@ void Compositor::notifyFrameCommitted()
void Compositor::sendPresentationFeedback(uint frame_token)
{
- gfx::PresentationFeedback dummyFeedback(base::TimeTicks::Now(), base::TimeDelta(), gfx::PresentationFeedback::Flags::kVSync);
- viz::FrameTimingDetails dummyDetails = {dummyFeedback};
+ viz::FrameTimingDetails dummyDetails = {base::TimeTicks::Now()};
m_presentations.emplace(frame_token, dummyDetails);
}
diff --git a/src/core/compositor/compositor_resource_tracker.cpp b/src/core/compositor/compositor_resource_tracker.cpp
index 741c2717c..1e7108571 100644
--- a/src/core/compositor/compositor_resource_tracker.cpp
+++ b/src/core/compositor/compositor_resource_tracker.cpp
@@ -250,7 +250,7 @@ void CompositorResourceTracker::scheduleRunSubmitCallback()
thread_local bool currentThreadIsUi = content::BrowserThread::CurrentlyOn(content::BrowserThread::UI);
if (currentThreadIsUi)
return runSubmitCallback();
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, { content::BrowserThread::UI, base::TaskPriority::USER_VISIBLE },
base::BindOnce(&CompositorResourceTracker::runSubmitCallback,
m_weakPtrFactory.GetWeakPtr()));
diff --git a/src/core/configure.json b/src/core/configure.json
index 9059575b9..55e68ab04 100644
--- a/src/core/configure.json
+++ b/src/core/configure.json
@@ -26,7 +26,6 @@
"webengine-extensions": "boolean",
"webengine-webrtc": "boolean",
"webengine-geolocation": "boolean",
- "webengine-v8-snapshot": "boolean",
"webengine-webchannel": "boolean",
"webengine-kerberos": "boolean",
"alsa": { "type": "boolean", "name": "webengine-alsa" },
@@ -104,7 +103,6 @@
"webengine-embedded-build": {
"label": "Embedded build",
"purpose": "Enables the embedded build configuration.",
- "section": "WebEngine",
"condition": "config.unix",
"autoDetect": "tests.webengine-embedded-build",
"output": [ "privateFeature" ]
@@ -114,14 +112,8 @@
"condition": "config.unix && libs.webengine-alsa",
"output": [ "privateFeature" ]
},
- "webengine-v8-snapshot": {
- "label" : "Use v8 snapshot",
- "purpose": "Enables the v8 snapshot, for fast v8 context creation",
- "output": [ "privateFeature" ]
- },
"webengine-v8-snapshot-support": {
"label" : "Building v8 snapshot supported",
- "autoDetect": "features.webengine-v8-snapshot",
"condition": "!config.unix || !features.cross_compile || arch.arm64 || tests.webengine-host-compiler",
"output": [ "privateFeature" ]
},
@@ -139,14 +131,12 @@
"webengine-pepper-plugins": {
"label": "Pepper Plugins",
"purpose": "Enables use of Pepper Flash plugins.",
- "section": "WebEngine",
"autoDetect": "!features.webengine-embedded-build",
"output": [ "privateFeature" ]
},
"webengine-printing-and-pdf": {
"label": "Printing and PDF",
"purpose": "Provides printing and output to PDF.",
- "section": "WebEngine",
"condition": "module.printsupport && features.printer",
"autoDetect": "!features.webengine-embedded-build",
"output": [ "privateFeature" ]
@@ -161,7 +151,6 @@
"webengine-proprietary-codecs": {
"label": "Proprietary Codecs",
"purpose": "Enables the use of proprietary codecs such as h.264/h.265 and MP3.",
- "section": "WebEngine",
"autoDetect": false,
"output": [ "privateFeature" ]
},
@@ -175,13 +164,11 @@
"webengine-spellchecker": {
"label": "Spellchecker",
"purpose": "Provides a spellchecker.",
- "section": "WebEngine",
"output": [ "publicFeature" ]
},
"webengine-native-spellchecker": {
"label": "Native Spellchecker",
"purpose": "Use the system's native spellchecking engine.",
- "section": "WebEngine",
"autoDetect": false,
"condition": "config.macos && features.webengine-spellchecker",
"output": [ "publicFeature" ]
@@ -197,7 +184,6 @@
"webengine-webrtc": {
"label": "WebRTC",
"purpose": "Provides WebRTC support.",
- "section": "WebEngine",
"autoDetect": "!features.webengine-embedded-build",
"output": [ "privateFeature" ]
},
@@ -264,7 +250,7 @@
},
{
"type": "warning",
- "condition": "config.linux && features.webengine-v8-snapshot && !features.webengine-v8-snapshot-support",
+ "condition": "config.unix && config.cross_compile && !features.webengine-v8-snapshot-support",
"message": "V8 snapshot cannot be built. Most likely, the 32-bit host compiler does not work. Please make sure you have 32-bit devel environment installed."
}
],
@@ -284,7 +270,6 @@
"webengine-webrtc",
"webengine-geolocation",
"webengine-webchannel",
- "webengine-v8-snapshot",
"webengine-kerberos",
"webengine-extensions",
{
@@ -295,7 +280,7 @@
{
"type": "feature",
"args": "webengine-v8-snapshot-support",
- "condition": "config.unix && config.cross_compile && features.webengine-v8-snapshot"
+ "condition": "config.unix && config.cross_compile"
},
{
"type": "feature",
diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp
index 29b6e09ed..a8d9e6ddc 100644
--- a/src/core/content_browser_client_qt.cpp
+++ b/src/core/content_browser_client_qt.cpp
@@ -41,31 +41,38 @@
#include "base/memory/ptr_util.h"
#include "base/optional.h"
+#include "base/path_service.h"
#include "base/strings/utf_string_conversions.h"
#include "base/message_loop/message_loop.h"
#include "base/task/post_task.h"
#include "base/threading/thread_restrictions.h"
+#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
#if QT_CONFIG(webengine_spellchecker)
#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
#endif
#include "components/guest_view/browser/guest_view_base.h"
+#include "components/navigation_interception/intercept_navigation_throttle.h"
+#include "components/navigation_interception/navigation_params.h"
#include "components/network_hints/browser/network_hints_message_filter.h"
+#include "components/spellcheck/spellcheck_buildflags.h"
#include "content/browser/renderer_host/render_view_host_delegate.h"
#include "content/common/url_schemes.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/client_certificate_delegate.h"
+#include "content/public/browser/file_url_loader.h"
#include "content/public/browser/media_observer.h"
+#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/resource_dispatcher_host_delegate.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/browser/web_contents_user_data.h"
+#include "content/public/browser/web_ui_url_loader_factory.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/main_function_params.h"
#include "content/public/common/service_manager_connection.h"
@@ -74,20 +81,24 @@
#include "content/public/common/user_agent.h"
#include "media/media_buildflags.h"
#include "extensions/buildflags/buildflags.h"
+#include "extensions/browser/extension_protocols.h"
+#include "extensions/browser/guest_view/web_view/web_view_guest.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "printing/buildflags/buildflags.h"
#include "qtwebengine/browser/qtwebengine_content_browser_overlay_manifest.h"
#include "qtwebengine/browser/qtwebengine_content_renderer_overlay_manifest.h"
-#include "qtwebengine/browser/qtwebengine_packaged_service_manifest.h"
-#include "qtwebengine/browser/qtwebengine_renderer_manifest.h"
#include "net/ssl/client_cert_identity.h"
#include "net/ssl/client_cert_store.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/features.h"
#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/sandbox/switches.h"
+#include "storage/browser/quota/quota_settings.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/mojom/insecure_input/insecure_input_service.mojom.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/base/ui_base_switches.h"
@@ -109,8 +120,12 @@
#include "devtools_manager_delegate_qt.h"
#include "login_delegate_qt.h"
#include "media_capture_devices_dispatcher.h"
-#include "net/network_delegate_qt.h"
-#include "net/url_request_context_getter_qt.h"
+#include "net/cookie_monster_delegate_qt.h"
+#include "net/custom_url_loader_factory.h"
+#include "net/proxying_restricted_cookie_manager_qt.h"
+#include "net/proxying_url_loader_factory_qt.h"
+#include "net/qrc_url_scheme_handler.h"
+#include "net/system_network_context_manager.h"
#include "platform_notification_service_qt.h"
#if QT_CONFIG(webengine_printing_and_pdf)
#include "printing/printing_message_filter_qt.h"
@@ -119,13 +134,14 @@
#include "profile_io_data_qt.h"
#include "quota_permission_context_qt.h"
#include "renderer_host/user_resource_controller_host.h"
-#include "service/service_qt.h"
#include "type_conversion.h"
+#include "web_contents_adapter_client.h"
#include "web_contents_delegate_qt.h"
#include "web_engine_context.h"
#include "web_engine_library_info.h"
#include "api/qwebenginecookiestore.h"
#include "api/qwebenginecookiestore_p.h"
+#include "api/qwebengineurlscheme.h"
#if defined(Q_OS_LINUX)
#include "global_descriptors_qt.h"
@@ -143,13 +159,16 @@
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
-#include "extensions/extensions_browser_client_qt.h"
+#include "content/public/browser/file_url_loader.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/guest_view/extensions_guest_view_message_filter.h"
#include "extensions/browser/io_thread_extension_message_filter.h"
#include "extensions/common/constants.h"
+
#include "common/extensions/extensions_client_qt.h"
-#include "renderer_host/resource_dispatcher_host_delegate_qt.h"
+#include "extensions/extension_web_contents_observer_qt.h"
+#include "extensions/extensions_browser_client_qt.h"
+#include "net/plugin_response_interceptor_url_loader_throttle.h"
#endif
#if BUILDFLAG(ENABLE_MOJO_MEDIA_IN_BROWSER_PROCESS)
@@ -157,8 +176,14 @@
#include "media/mojo/services/media_service_factory.h"
#endif
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
+#include "components/spellcheck/common/spellcheck.mojom.h"
+#endif
+
#include <QGuiApplication>
#include <QLocale>
+#include <QStandardPaths>
#if QT_CONFIG(opengl)
# include <QOpenGLContext>
# include <QOpenGLExtraFunctions>
@@ -271,54 +296,36 @@ std::unique_ptr<content::BrowserMainParts> ContentBrowserClientQt::CreateBrowser
return std::make_unique<BrowserMainPartsQt>();
}
-void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost* host,
- service_manager::mojom::ServiceRequest *service_request)
+void ContentBrowserClientQt::RenderProcessWillLaunch(content::RenderProcessHost *host)
{
const int id = host->GetID();
Profile *profile = Profile::FromBrowserContext(host->GetBrowserContext());
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&net::URLRequestContextGetter::GetURLRequestContext, base::Unretained(profile->GetRequestContext())),
- base::BindOnce(&ContentBrowserClientQt::AddNetworkHintsMessageFilter, base::Unretained(this), id));
+
+ host->AddFilter(new network_hints::NetworkHintsMessageFilter(id));
+
+ // Allow requesting custom schemes.
+ const auto policy = content::ChildProcessSecurityPolicy::GetInstance();
+ const auto profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter();
+ for (const QByteArray &scheme : profileAdapter->customUrlSchemes())
+ policy->GrantRequestScheme(id, scheme.toStdString());
// FIXME: Add a settings variable to enable/disable the file scheme.
- content::ChildProcessSecurityPolicy::GetInstance()->GrantRequestScheme(id, url::kFileScheme);
- static_cast<ProfileQt*>(host->GetBrowserContext())->m_profileAdapter->userResourceController()->renderProcessStartedWithHost(host);
+ policy->GrantRequestScheme(id, url::kFileScheme);
+ profileAdapter->userResourceController()->renderProcessStartedWithHost(host);
host->AddFilter(new BrowserMessageFilterQt(id, profile));
#if QT_CONFIG(webengine_printing_and_pdf)
- host->AddFilter(new PrintingMessageFilterQt(host->GetID()));
+ host->AddFilter(new PrintingMessageFilterQt(id));
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
- host->AddFilter(new extensions::ExtensionMessageFilter(host->GetID(), host->GetBrowserContext()));
- host->AddFilter(new extensions::IOThreadExtensionMessageFilter(host->GetID(), host->GetBrowserContext()));
- host->AddFilter(new extensions::ExtensionsGuestViewMessageFilter(host->GetID(), host->GetBrowserContext()));
+ host->AddFilter(new extensions::ExtensionMessageFilter(id, profile));
+ host->AddFilter(new extensions::IOThreadExtensionMessageFilter());
+ host->AddFilter(new extensions::ExtensionsGuestViewMessageFilter(id, profile));
#endif //ENABLE_EXTENSIONS
bool is_incognito_process = profile->IsOffTheRecord();
qtwebengine::mojom::RendererConfigurationAssociatedPtr renderer_configuration;
host->GetChannel()->GetRemoteAssociatedInterface(&renderer_configuration);
renderer_configuration->SetInitialConfiguration(is_incognito_process);
-
- mojo::PendingRemote<service_manager::mojom::Service> service;
- *service_request = service.InitWithNewPipeAndPassReceiver();
- service_manager::Identity renderer_identity = host->GetChildIdentity();
- mojo::Remote<service_manager::mojom::ProcessMetadata> metadata;
- ServiceQt::GetInstance()->connector()->RegisterServiceInstance(
- service_manager::Identity("qtwebengine_renderer",
- renderer_identity.instance_group(),
- renderer_identity.instance_id(),
- base::Token::CreateRandom()),
- std::move(service), metadata.BindNewPipeAndPassReceiver());
-}
-
-void ContentBrowserClientQt::ResourceDispatcherHostCreated()
-{
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- m_resourceDispatcherHostDelegate.reset(new ResourceDispatcherHostDelegateQt);
-#else
- m_resourceDispatcherHostDelegate.reset(new content::ResourceDispatcherHostDelegate);
-#endif
- content::ResourceDispatcherHost::Get()->SetDelegate(m_resourceDispatcherHostDelegate.get());
}
gl::GLShareGroup *ContentBrowserClientQt::GetInProcessGpuShareGroup()
@@ -353,9 +360,10 @@ scoped_refptr<content::QuotaPermissionContext> ContentBrowserClientQt::CreateQuo
void ContentBrowserClientQt::GetQuotaSettings(content::BrowserContext* context,
content::StoragePartition* partition,
- storage::OptionalQuotaSettingsCallback callback)
+ base::OnceCallback<void(base::Optional<storage::QuotaSettings>)> callback)
{
- storage::GetNominalDynamicSettings(partition->GetPath(), context->IsOffTheRecord(), storage::GetDefaultDiskInfoHelper(), std::move(callback));
+ storage::GetNominalDynamicSettings(partition->GetPath(), context->IsOffTheRecord(),
+ storage::GetDefaultDiskInfoHelper(), std::move(callback));
}
// Copied from chrome/browser/ssl/ssl_error_handler.cc:
@@ -390,7 +398,6 @@ void ContentBrowserClientQt::AllowCertificateError(content::WebContents *webCont
const GURL &request_url,
bool is_main_frame_request,
bool strict_enforcement,
- bool expired_previous_decision,
const base::Callback<void(content::CertificateRequestResultType)> &callback)
{
WebContentsDelegateQt* contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
@@ -459,12 +466,24 @@ void ContentBrowserClientQt::AppendExtraCommandLineSwitches(base::CommandLine* c
void ContentBrowserClientQt::GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes)
{
+ ContentBrowserClient::GetAdditionalWebUISchemes(additional_schemes);
additional_schemes->push_back(content::kChromeDevToolsScheme);
}
void ContentBrowserClientQt::GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes)
{
- additional_schemes->push_back(content::kChromeDevToolsScheme);
+ ContentBrowserClient::GetAdditionalViewSourceSchemes(additional_schemes);
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ additional_schemes->push_back(extensions::kExtensionScheme);
+#endif
+}
+
+void ContentBrowserClientQt::GetAdditionalAllowedSchemesForFileSystem(std::vector<std::string>* additional_schemes)
+{
+ ContentBrowserClient::GetAdditionalAllowedSchemesForFileSystem(additional_schemes);
+ additional_schemes->push_back(content::kChromeDevToolsScheme);
+ additional_schemes->push_back(content::kChromeUIScheme);
}
#if defined(Q_OS_LINUX)
@@ -569,6 +588,17 @@ void ContentBrowserClientQt::BindInterfaceRequestFromFrame(content::RenderFrameH
m_frameInterfaces->TryBindInterface(interface_name, &interface_pipe);
}
+void ContentBrowserClientQt::BindHostReceiverForRenderer(content::RenderProcessHost *render_process_host,
+ mojo::GenericPendingReceiver receiver)
+{
+#if BUILDFLAG(ENABLE_SPELLCHECK)
+ if (auto host_receiver = receiver.As<spellcheck::mojom::SpellCheckHost>()) {
+ SpellCheckHostChromeImpl::Create(render_process_host->GetID(), std::move(host_receiver));
+ return;
+ }
+#endif // BUILDFLAG(ENABLE_SPELLCHECK)
+}
+
void ContentBrowserClientQt::RunServiceInstance(const service_manager::Identity &identity,
mojo::PendingReceiver<service_manager::mojom::Service> *receiver)
{
@@ -582,17 +612,6 @@ void ContentBrowserClientQt::RunServiceInstance(const service_manager::Identity
content::ContentBrowserClient::RunServiceInstance(identity, receiver);
}
-void ContentBrowserClientQt::RunServiceInstanceOnIOThread(const service_manager::Identity &identity,
- mojo::PendingReceiver<service_manager::mojom::Service> *receiver)
-{
- if (identity.name() == "qtwebengine") {
- ServiceQt::GetInstance()->CreateServiceQtRequestHandler().Run(std::move(*receiver));
- return;
- }
-
- content::ContentBrowserClient::RunServiceInstance(identity, receiver);
-}
-
base::Optional<service_manager::Manifest> ContentBrowserClientQt::GetServiceManifestOverlay(base::StringPiece name)
{
if (name == content::mojom::kBrowserServiceName)
@@ -605,9 +624,7 @@ base::Optional<service_manager::Manifest> ContentBrowserClientQt::GetServiceMani
std::vector<service_manager::Manifest> ContentBrowserClientQt::GetExtraServiceManifests()
{
- auto manifests = GetQtWebEnginePackagedServiceManifests();
- manifests.push_back(GetQtWebEngineRendererManifest());
- return manifests;
+ return { };
}
bool ContentBrowserClientQt::CanCreateWindow(
@@ -659,19 +676,6 @@ std::unique_ptr<device::LocationProvider> ContentBrowserClientQt::OverrideSystem
}
#endif
-void ContentBrowserClientQt::AddNetworkHintsMessageFilter(int render_process_id, net::URLRequestContext *context)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
- content::RenderProcessHost* host = content::RenderProcessHost::FromID(render_process_id);
- if (!host)
- return;
-
- content::BrowserMessageFilter *network_hints_message_filter =
- new network_hints::NetworkHintsMessageFilter(render_process_id);
- host->AddFilter(network_hints_message_filter);
-}
-
bool ContentBrowserClientQt::ShouldEnableStrictSiteIsolation()
{
// mirroring AwContentBrowserClient, CastContentBrowserClient and
@@ -679,29 +683,29 @@ bool ContentBrowserClientQt::ShouldEnableStrictSiteIsolation()
return false;
}
-bool ContentBrowserClientQt::WillCreateRestrictedCookieManager(network::mojom::RestrictedCookieManagerRole role,
- content::BrowserContext *browser_context,
- const url::Origin &origin,
- bool is_service_worker,
- int process_id,
- int routing_id,
- network::mojom::RestrictedCookieManagerRequest *request)
-{
- base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&ProfileIODataQt::CreateRestrictedCookieManager,
- ProfileIODataQt::FromBrowserContext(browser_context)->getWeakPtrOnUIThread(),
- std::move(*request),
- role, origin, is_service_worker, process_id, routing_id));
- return true;
-}
-
-bool ContentBrowserClientQt::AllowAppCacheOnIO(const GURL &manifest_url,
- const GURL &first_party,
- content::ResourceContext *context)
+bool ContentBrowserClientQt::WillCreateRestrictedCookieManager(
+ network::mojom::RestrictedCookieManagerRole role,
+ content::BrowserContext *browser_context,
+ const url::Origin & /*origin*/,
+ const GURL & /*site_for_cookies*/,
+ const url::Origin & /*top_frame_origin*/,
+ bool is_service_worker,
+ int process_id,
+ int routing_id,
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> *receiver)
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(manifest_url));
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> orig_receiver = std::move(*receiver);
+
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> target_rcm_remote;
+ *receiver = target_rcm_remote.InitWithNewPipeAndPassReceiver();
+
+ ProxyingRestrictedCookieManagerQt::CreateAndBind(
+ ProfileIODataQt::FromBrowserContext(browser_context),
+ std::move(target_rcm_remote),
+ is_service_worker, process_id, routing_id,
+ std::move(orig_receiver));
+
+ return false; // only made a proxy, still need the actual impl to be made.
}
bool ContentBrowserClientQt::AllowAppCache(const GURL &manifest_url,
@@ -712,45 +716,68 @@ bool ContentBrowserClientQt::AllowAppCache(const GURL &manifest_url,
return static_cast<ProfileQt *>(context)->profileAdapter()->cookieStore()->d_func()->canAccessCookies(toQt(first_party), toQt(manifest_url));
}
-bool ContentBrowserClientQt::AllowServiceWorker(const GURL &scope,
- const GURL &first_party,
- const GURL & /*script_url*/,
- content::ResourceContext *context,
- base::RepeatingCallback<content::WebContents*()> wc_getter)
+bool ContentBrowserClientQt::AllowServiceWorkerOnIO(const GURL &scope,
+ const GURL &site_for_cookies,
+ const base::Optional<url::Origin> & /*top_frame_origin*/,
+ const GURL & /*script_url*/,
+ content::ResourceContext *context,
+ base::RepeatingCallback<content::WebContents*()> wc_getter)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
// FIXME: Chrome also checks if javascript is enabled here to check if has been disabled since the service worker
// was started.
- return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(first_party), toQt(scope));
+ return ProfileIODataQt::FromResourceContext(context)->canGetCookies(toQt(site_for_cookies), toQt(scope));
+}
+
+bool ContentBrowserClientQt::AllowServiceWorkerOnUI(const GURL &scope,
+ const GURL &site_for_cookies,
+ const base::Optional<url::Origin> & /*top_frame_origin*/,
+ const GURL & /*script_url*/,
+ content::BrowserContext *context,
+ base::RepeatingCallback<content::WebContents*()> wc_getter)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ // FIXME: Chrome also checks if javascript is enabled here to check if has been disabled since the service worker
+ // was started.
+ return static_cast<ProfileQt *>(context)->profileAdapter()->cookieStore()->d_func()->canAccessCookies(toQt(site_for_cookies), toQt(scope));
}
// We control worker access to FS and indexed-db using cookie permissions, this is mirroring Chromium's logic.
void ContentBrowserClientQt::AllowWorkerFileSystem(const GURL &url,
- content::ResourceContext *context,
+ content::BrowserContext *context,
const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/,
- base::Callback<void(bool)> callback)
+ base::OnceCallback<void(bool)> callback)
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- callback.Run(ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(url), QByteArray(), toQt(url)));
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ std::move(callback).Run(
+ static_cast<ProfileQt *>(context)->profileAdapter()->cookieStore()->d_func()->canAccessCookies(toQt(url), toQt(url)));
}
bool ContentBrowserClientQt::AllowWorkerIndexedDB(const GURL &url,
- content::ResourceContext *context,
+ content::BrowserContext *context,
const std::vector<content::GlobalFrameRoutingId> &/*render_frames*/)
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- return ProfileIODataQt::FromResourceContext(context)->canSetCookie(toQt(url), QByteArray(), toQt(url));
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ return static_cast<ProfileQt *>(context)->profileAdapter()->cookieStore()->d_func()->canAccessCookies(toQt(url), toQt(url));
}
static void LaunchURL(const GURL& url,
- const content::ResourceRequestInfo::WebContentsGetter& web_contents_getter,
+ const content::WebContents::Getter& web_contents_getter,
ui::PageTransition page_transition, bool is_main_frame, bool has_user_gesture)
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
content::WebContents* webContents = web_contents_getter.Run();
if (!webContents)
return;
+
+ ProtocolHandlerRegistry* protocolHandlerRegistry =
+ ProtocolHandlerRegistryFactory::GetForBrowserContext(
+ webContents->GetBrowserContext());
+ if (protocolHandlerRegistry &&
+ protocolHandlerRegistry->IsHandledProtocol(url.scheme()))
+ return;
+
WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt*>(webContents->GetDelegate());
contentsDelegate->launchExternalURL(toQt(url), page_transition, is_main_frame, has_user_gesture);
}
@@ -758,36 +785,36 @@ static void LaunchURL(const GURL& url,
bool ContentBrowserClientQt::HandleExternalProtocol(
const GURL &url,
- content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ content::WebContents::Getter web_contents_getter,
int child_id,
content::NavigationUIData *navigation_data,
bool is_main_frame,
ui::PageTransition page_transition,
bool has_user_gesture,
+ const base::Optional<url::Origin> &initiating_origin,
network::mojom::URLLoaderFactoryPtr *out_factory)
{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+// Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
Q_UNUSED(child_id);
Q_UNUSED(navigation_data);
Q_UNUSED(out_factory);
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&LaunchURL,
- url,
- web_contents_getter,
- page_transition,
- is_main_frame,
- has_user_gesture));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(&LaunchURL,
+ url,
+ web_contents_getter,
+ page_transition,
+ is_main_frame,
+ has_user_gesture));
return true;
}
namespace {
// Copied from chrome/browser/chrome_content_browser_client.cc
-template<class HandlerRegistry>
-class ProtocolHandlerThrottle : public content::URLLoaderThrottle
+class ProtocolHandlerThrottle : public blink::URLLoaderThrottle
{
public:
- explicit ProtocolHandlerThrottle(const HandlerRegistry &protocol_handler_registry)
+ explicit ProtocolHandlerThrottle(ProtocolHandlerRegistry *protocol_handler_registry)
: protocol_handler_registry_(protocol_handler_registry)
{
}
@@ -816,34 +843,112 @@ private:
*url = translated_url;
}
- HandlerRegistry protocol_handler_registry_;
+ ProtocolHandlerRegistry *protocol_handler_registry_;
};
} // namespace
-std::vector<std::unique_ptr<content::URLLoaderThrottle>>
-ContentBrowserClientQt::CreateURLLoaderThrottlesOnIO(
- const network::ResourceRequest & /*request*/, content::ResourceContext *resource_context,
+std::vector<std::unique_ptr<blink::URLLoaderThrottle>>
+ContentBrowserClientQt::CreateURLLoaderThrottles(
+ const network::ResourceRequest &request, content::BrowserContext *browser_context,
const base::RepeatingCallback<content::WebContents *()> & /*wc_getter*/,
- content::NavigationUIData * /*navigation_ui_data*/, int /*frame_tree_node_id*/)
+ content::NavigationUIData * /*navigation_ui_data*/, int frame_tree_node_id)
{
- std::vector<std::unique_ptr<content::URLLoaderThrottle>> result;
- ProfileIODataQt *ioData = ProfileIODataQt::FromResourceContext(resource_context);
- result.push_back(std::make_unique<ProtocolHandlerThrottle<
- scoped_refptr<ProtocolHandlerRegistry::IOThreadDelegate>>>(
- ioData->protocolHandlerRegistryIOThreadDelegate()));
+ std::vector<std::unique_ptr<blink::URLLoaderThrottle>> result;
+ result.push_back(std::make_unique<ProtocolHandlerThrottle>(
+ ProtocolHandlerRegistryFactory::GetForBrowserContext(browser_context)));
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ result.push_back(std::make_unique<PluginResponseInterceptorURLLoaderThrottle>(
+ browser_context, request.resource_type, frame_tree_node_id));
+#endif
return result;
}
-std::vector<std::unique_ptr<content::URLLoaderThrottle>>
-ContentBrowserClientQt::CreateURLLoaderThrottles(
- const network::ResourceRequest &request, content::BrowserContext *browser_context,
- const base::RepeatingCallback<content::WebContents *()> &wc_getter,
- content::NavigationUIData *navigation_ui_data, int frame_tree_node_id)
+WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition)
{
- std::vector<std::unique_ptr<content::URLLoaderThrottle>> result;
- result.push_back(std::make_unique<ProtocolHandlerThrottle<ProtocolHandlerRegistry *>>(
- ProtocolHandlerRegistryFactory::GetForBrowserContext(browser_context)));
- return result;
+ if (ui::PageTransitionIsRedirect(transition))
+ return WebContentsAdapterClient::RedirectNavigation;
+
+ int32_t qualifier = ui::PageTransitionGetQualifier(transition);
+
+ if (qualifier & ui::PAGE_TRANSITION_FORWARD_BACK)
+ return WebContentsAdapterClient::BackForwardNavigation;
+
+ ui::PageTransition strippedTransition = ui::PageTransitionStripQualifier(transition);
+
+ switch (strippedTransition) {
+ case ui::PAGE_TRANSITION_LINK:
+ return WebContentsAdapterClient::LinkNavigation;
+ case ui::PAGE_TRANSITION_TYPED:
+ return WebContentsAdapterClient::TypedNavigation;
+ case ui::PAGE_TRANSITION_FORM_SUBMIT:
+ return WebContentsAdapterClient::FormSubmittedNavigation;
+ case ui::PAGE_TRANSITION_RELOAD:
+ return WebContentsAdapterClient::ReloadNavigation;
+ default:
+ return WebContentsAdapterClient::OtherNavigation;
+ }
+}
+
+static bool navigationThrottleCallback(content::WebContents *source,
+ const navigation_interception::NavigationParams &params)
+{
+ // We call navigationRequested later in launchExternalUrl for external protocols.
+ // The is_external_protocol parameter here is not fully accurate though,
+ // and doesn't know about profile specific custom URL schemes.
+ ProfileQt *profile = static_cast<ProfileQt *>(source->GetBrowserContext());
+ if (params.is_external_protocol() && !profile->profileAdapter()->urlSchemeHandler(toQByteArray(params.url().scheme())))
+ return false;
+ int navigationRequestAction = WebContentsAdapterClient::AcceptRequest;
+ WebContentsDelegateQt *delegate = static_cast<WebContentsDelegateQt *>(source->GetDelegate());
+ WebContentsAdapterClient *client = delegate->adapterClient();
+ client->navigationRequested(pageTransitionToNavigationType(params.transition_type()),
+ toQt(params.url()),
+ navigationRequestAction,
+ params.is_main_frame());
+ return navigationRequestAction == static_cast<int>(WebContentsAdapterClient::IgnoreRequest);
+}
+
+std::vector<std::unique_ptr<content::NavigationThrottle>> ContentBrowserClientQt::CreateThrottlesForNavigation(
+ content::NavigationHandle *navigation_handle)
+{
+ std::vector<std::unique_ptr<content::NavigationThrottle>> throttles;
+ throttles.push_back(std::make_unique<navigation_interception::InterceptNavigationThrottle>(
+ navigation_handle,
+ base::BindRepeating(&navigationThrottleCallback),
+ navigation_interception::SynchronyMode::kSync));
+ return throttles;
+}
+
+bool ContentBrowserClientQt::IsHandledURL(const GURL &url)
+{
+ static const char *const kProtocolList[] = {
+ url::kFileScheme,
+ content::kChromeDevToolsScheme,
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ extensions::kExtensionScheme,
+#endif
+ content::kChromeUIScheme,
+ url::kDataScheme,
+ url::kAboutScheme,
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ url::kFtpScheme,
+#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ url::kBlobScheme,
+ url::kFileSystemScheme,
+ url::kQrcScheme,
+ };
+
+ // We don't check url.IsCustom() here because we don't
+ // know if the registered protocol is installed in the
+ // profile that will be used to load the URL.
+
+ const std::string scheme = url.scheme();
+
+ for (const char *protocol : kProtocolList) {
+ if (scheme == protocol)
+ return true;
+ }
+ return net::URLRequest::IsHandledProtocol(scheme);
}
std::unique_ptr<content::LoginDelegate> ContentBrowserClientQt::CreateLoginDelegate(
@@ -875,6 +980,35 @@ bool ContentBrowserClientQt::ShouldUseProcessPerSite(content::BrowserContext* br
return ContentBrowserClient::ShouldUseProcessPerSite(browser_context, effective_url);
}
+bool ContentBrowserClientQt::DoesSiteRequireDedicatedProcess(content::BrowserContext *browser_context,
+ const GURL &effective_site_url)
+{
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ if (effective_site_url.SchemeIs(extensions::kExtensionScheme))
+ return true;
+#endif
+ return ContentBrowserClient::DoesSiteRequireDedicatedProcess(browser_context, effective_site_url);
+}
+
+bool ContentBrowserClientQt::ShouldUseSpareRenderProcessHost(content::BrowserContext *browser_context,
+ const GURL &site_url)
+{
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ if (site_url.SchemeIs(extensions::kExtensionScheme))
+ return false;
+#endif
+ return ContentBrowserClient::ShouldUseSpareRenderProcessHost(browser_context, site_url);
+}
+
+bool ContentBrowserClientQt::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(base::StringPiece scheme)
+{
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ return scheme == extensions::kExtensionScheme;
+#else
+ return false;
+#endif
+}
+
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)
@@ -887,4 +1021,189 @@ std::string ContentBrowserClientQt::GetProduct()
return productName.toStdString();
}
+scoped_refptr<network::SharedURLLoaderFactory> ContentBrowserClientQt::GetSystemSharedURLLoaderFactory()
+{
+ if (!SystemNetworkContextManager::GetInstance())
+ return nullptr;
+ return SystemNetworkContextManager::GetInstance()->GetSharedURLLoaderFactory();
+}
+
+network::mojom::NetworkContext *ContentBrowserClientQt::GetSystemNetworkContext()
+{
+ if (!SystemNetworkContextManager::GetInstance())
+ return nullptr;
+ return SystemNetworkContextManager::GetInstance()->GetContext();
+}
+
+void ContentBrowserClientQt::OnNetworkServiceCreated(network::mojom::NetworkService *network_service)
+{
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return;
+
+ if (!SystemNetworkContextManager::GetInstance())
+ SystemNetworkContextManager::CreateInstance();
+
+ // Need to set up global NetworkService state before anything else uses it.
+ SystemNetworkContextManager::GetInstance()->OnNetworkServiceCreated(network_service);
+}
+
+mojo::Remote<network::mojom::NetworkContext> ContentBrowserClientQt::CreateNetworkContext(
+ content::BrowserContext *context,
+ bool in_memory,
+ const base::FilePath &relative_partition_path)
+{
+ mojo::Remote<network::mojom::NetworkContext> network_context;
+ // ### do we need to pass in_memory and relative_partition_path to ProfileIODataQt::CreateNetworkContextParams() ?
+ network::mojom::NetworkContextParamsPtr context_params = ProfileIODataQt::FromBrowserContext(context)->CreateNetworkContextParams();
+ content::GetNetworkService()->CreateNetworkContext(
+ network_context.BindNewPipeAndPassReceiver(), std::move(context_params));
+
+ network::mojom::CookieManagerPtrInfo cookie_manager_info;
+ network_context->GetCookieManager(mojo::MakeRequest(&cookie_manager_info));
+ ProfileIODataQt::FromBrowserContext(context)->cookieDelegate()->setMojoCookieManager(std::move(cookie_manager_info));
+
+ return network_context;
+}
+
+std::vector<base::FilePath> ContentBrowserClientQt::GetNetworkContextsParentDirectory()
+{
+ return {
+ toFilePath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)),
+ toFilePath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) };
+}
+
+void ContentBrowserClientQt::RegisterNonNetworkNavigationURLLoaderFactories(int frame_tree_node_id,
+ NonNetworkURLLoaderFactoryMap *factories)
+{
+ DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
+ content::WebContents *web_contents = content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
+ Profile *profile = Profile::FromBrowserContext(web_contents->GetBrowserContext());
+ ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter();
+
+ for (const QByteArray &scheme : profileAdapter->customUrlSchemes())
+ factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter));
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ factories->emplace(
+ extensions::kExtensionScheme,
+ extensions::CreateExtensionNavigationURLLoaderFactory(profile,
+ !!extensions::WebViewGuest::FromWebContents(web_contents)));
+#endif
+}
+
+void ContentBrowserClientQt::RegisterNonNetworkWorkerMainResourceURLLoaderFactories(content::BrowserContext *browser_context,
+ NonNetworkURLLoaderFactoryMap *factories)
+{
+ DCHECK(base::FeatureList::IsEnabled(network::features::kNetworkService));
+ Profile *profile = Profile::FromBrowserContext(browser_context);
+ ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter();
+
+ for (const QByteArray &scheme : profileAdapter->customUrlSchemes())
+ factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter));
+}
+
+void ContentBrowserClientQt::RegisterNonNetworkSubresourceURLLoaderFactories(int render_process_id, int render_frame_id,
+ NonNetworkURLLoaderFactoryMap *factories)
+{
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return;
+ content::RenderProcessHost *process_host = content::RenderProcessHost::FromID(render_process_id);
+ Profile *profile = Profile::FromBrowserContext(process_host->GetBrowserContext());
+ ProfileAdapter *profileAdapter = static_cast<ProfileQt *>(profile)->profileAdapter();
+
+ for (const QByteArray &scheme : profileAdapter->customUrlSchemes())
+ factories->emplace(scheme.toStdString(), CreateCustomURLLoaderFactory(profileAdapter));
+
+ content::RenderFrameHost *frame_host = content::RenderFrameHost::FromID(render_process_id, render_frame_id);
+ content::WebContents *web_contents = content::WebContents::FromRenderFrameHost(frame_host);
+ GURL url;
+ if (web_contents)
+ url = web_contents->GetVisibleURL();
+
+ // Install file scheme if necessary:
+ // FIXME: "extension -> file" will not be needed after switching to using transferable url loaders and guest views.
+ // FIXME: "qrc -> file" should be reconsidered for Qt6.
+ bool install_file_scheme = url.SchemeIs("qrc");
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ install_file_scheme = install_file_scheme || url.SchemeIs(extensions::kExtensionScheme);
+#endif
+ if (!install_file_scheme && web_contents) {
+ const auto *settings = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate())->webEngineSettings();
+ if (settings->testAttribute(WebEngineSettings::LocalContentCanAccessFileUrls)) {
+ for (const auto &local_scheme : url::GetLocalSchemes()) {
+ if (url.SchemeIs(local_scheme)) {
+ install_file_scheme = true;
+ break;
+ }
+ }
+ }
+ }
+
+ if (install_file_scheme && factories->find(url::kFileScheme) == factories->end()) {
+ auto file_factory = content::CreateFileURLLoaderFactory(profile->GetPath(),
+ profile->GetSharedCorsOriginAccessList());
+ factories->emplace(url::kFileScheme, std::move(file_factory));
+ }
+
+#if BUILDFLAG(ENABLE_EXTENSIONS)
+ auto factory = extensions::CreateExtensionURLLoaderFactory(render_process_id, render_frame_id);
+ if (factory)
+ factories->emplace(extensions::kExtensionScheme, std::move(factory));
+
+ if (!web_contents)
+ return;
+
+ extensions::ExtensionWebContentsObserverQt *web_observer =
+ extensions::ExtensionWebContentsObserverQt::FromWebContents(web_contents);
+ if (!web_observer)
+ return;
+
+ const extensions::Extension *extension = web_observer->GetExtensionFromFrame(frame_host, false);
+ if (!extension)
+ return;
+
+ std::vector<std::string> allowed_webui_hosts;
+ // Support for chrome:// scheme if appropriate.
+ if ((extension->is_extension() || extension->is_platform_app()) &&
+ extensions::Manifest::IsComponentLocation(extension->location())) {
+ // Components of chrome that are implemented as extensions or platform apps
+ // are allowed to use chrome://resources/ and chrome://theme/ URLs.
+ allowed_webui_hosts.emplace_back(content::kChromeUIResourcesHost);
+ }
+ if (!allowed_webui_hosts.empty()) {
+ factories->emplace(content::kChromeUIScheme,
+ content::CreateWebUIURLLoader(frame_host,
+ content::kChromeUIScheme,
+ std::move(allowed_webui_hosts)));
+ }
+#endif
+}
+
+bool ContentBrowserClientQt::WillCreateURLLoaderFactory(
+ content::BrowserContext *browser_context,
+ content::RenderFrameHost *frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin &request_initiator,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> *factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> *header_client,
+ bool *bypass_redirect_checks)
+{
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return false;
+
+ auto proxied_receiver = std::move(*factory_receiver);
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info;
+ *factory_receiver = mojo::MakeRequest(&target_factory_info);
+ int process_id = (type == URLLoaderFactoryType::kNavigation) ? 0 : render_process_id;
+
+ base::PostTask(FROM_HERE, { content::BrowserThread::IO },
+ base::BindOnce(&ProxyingURLLoaderFactoryQt::CreateProxy, process_id,
+ browser_context->GetResourceContext(),
+ static_cast<content::RenderFrameHostImpl*>(frame),
+ std::move(proxied_receiver),
+ std::move(target_factory_info)));
+ return true;
+}
+
} // namespace QtWebEngineCore
diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h
index f5b03a8d9..d828d44b6 100644
--- a/src/core/content_browser_client_qt.h
+++ b/src/core/content_browser_client_qt.h
@@ -78,21 +78,19 @@ class BrowserMainPartsQt;
class ProfileQt;
class ShareGroupQtQuick;
-class ContentBrowserClientQt : public content::ContentBrowserClient {
-
+class ContentBrowserClientQt : public content::ContentBrowserClient
+{
public:
ContentBrowserClientQt();
~ContentBrowserClientQt();
std::unique_ptr<content::BrowserMainParts> CreateBrowserMainParts(const content::MainFunctionParams&) override;
- void RenderProcessWillLaunch(content::RenderProcessHost *host,
- service_manager::mojom::ServiceRequest* service_request) override;
- void ResourceDispatcherHostCreated() override;
+ void RenderProcessWillLaunch(content::RenderProcessHost *host) override;
gl::GLShareGroup* GetInProcessGpuShareGroup() override;
content::MediaObserver* GetMediaObserver() override;
scoped_refptr<content::QuotaPermissionContext> CreateQuotaPermissionContext() override;
void GetQuotaSettings(content::BrowserContext *context,
- content::StoragePartition *partition,
- storage::OptionalQuotaSettingsCallback callback) override;
+ content::StoragePartition *partition,
+ base::OnceCallback<void(base::Optional<storage::QuotaSettings>)> callback) override;
void OverrideWebkitPrefs(content::RenderViewHost *, content::WebPreferences *) override;
void AllowCertificateError(content::WebContents *web_contents,
int cert_error,
@@ -100,7 +98,6 @@ public:
const GURL &request_url,
bool is_main_frame_request,
bool strict_enforcement,
- bool expired_previous_decision,
const base::Callback<void(content::CertificateRequestResultType)> &callback) override;
base::OnceClosure SelectClientCertificate(content::WebContents* web_contents,
net::SSLCertRequestInfo* cert_request_info,
@@ -116,14 +113,15 @@ public:
void GetAdditionalViewSourceSchemes(std::vector<std::string>* additional_schemes) override;
void GetAdditionalWebUISchemes(std::vector<std::string>* additional_schemes) override;
+ void GetAdditionalAllowedSchemesForFileSystem(std::vector<std::string>* additional_schemes) override;
void BindInterfaceRequestFromFrame(content::RenderFrameHost* render_frame_host,
const std::string& interface_name,
mojo::ScopedMessagePipeHandle interface_pipe) override;
+ void BindHostReceiverForRenderer(content::RenderProcessHost *render_process_host,
+ mojo::GenericPendingReceiver receiver) override;
void RunServiceInstance(const service_manager::Identity &identity,
mojo::PendingReceiver<service_manager::mojom::Service> *receiver) override;
- void RunServiceInstanceOnIOThread(const service_manager::Identity &identity,
- mojo::PendingReceiver<service_manager::mojom::Service> *receiver) override;
std::vector<service_manager::Manifest> GetExtraServiceManifests() override;
base::Optional<service_manager::Manifest> GetServiceManifestOverlay(base::StringPiece name) override;
@@ -142,41 +140,53 @@ public:
bool *no_javascript_access) override;
bool ShouldEnableStrictSiteIsolation() override;
- bool WillCreateRestrictedCookieManager(network::mojom::RestrictedCookieManagerRole role,
- content::BrowserContext *browser_context,
- const url::Origin& origin,
- bool is_service_worker,
- int process_id,
- int routing_id,
- network::mojom::RestrictedCookieManagerRequest *request) override;
-
- bool AllowAppCacheOnIO(const GURL& manifest_url,
- const GURL& first_party,
- content::ResourceContext* context) override;
- bool AllowAppCache(const GURL& manifest_url,
- const GURL& first_party,
- content::BrowserContext* context) override;
-
- bool AllowServiceWorker(const GURL& scope,
- const GURL& first_party,
- const GURL& script_url,
- content::ResourceContext* context,
- base::RepeatingCallback<content::WebContents*()> wc_getter) override;
+ bool WillCreateRestrictedCookieManager(
+ network::mojom::RestrictedCookieManagerRole role,
+ content::BrowserContext *browser_context,
+ const url::Origin &origin,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ bool is_service_worker,
+ int process_id,
+ int routing_id,
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> *receiver) override;
+
+ bool AllowAppCache(const GURL &manifest_url,
+ const GURL &first_party,
+ content::BrowserContext *context) override;
+
+ bool AllowServiceWorkerOnIO(const GURL &scope,
+ const GURL &site_for_cookies,
+ const base::Optional<url::Origin> &top_frame_origin,
+ const GURL &script_url,
+ content::ResourceContext *context,
+ base::RepeatingCallback<content::WebContents*()> wc_getter) override;
+
+ bool AllowServiceWorkerOnUI(const GURL &scope,
+ const GURL &site_for_cookies,
+ const base::Optional<url::Origin> &top_frame_origin,
+ const GURL &script_url,
+ content::BrowserContext *context,
+ base::RepeatingCallback<content::WebContents*()> wc_getter) override;
void AllowWorkerFileSystem(const GURL &url,
- content::ResourceContext *context,
+ content::BrowserContext *context,
const std::vector<content::GlobalFrameRoutingId> &render_frames,
- base::Callback<void(bool)> callback) override;
+ base::OnceCallback<void(bool)> callback) override;
bool AllowWorkerIndexedDB(const GURL &url,
- content::ResourceContext *context,
+ content::BrowserContext *context,
const std::vector<content::GlobalFrameRoutingId> &render_frames) override;
#if QT_CONFIG(webengine_geolocation)
std::unique_ptr<device::LocationProvider> OverrideSystemLocationProvider() override;
#endif
bool ShouldIsolateErrorPage(bool in_main_frame) override;
- bool ShouldUseProcessPerSite(content::BrowserContext* browser_context, const GURL& effective_url) override;
+ bool ShouldUseProcessPerSite(content::BrowserContext *browser_context, const GURL &effective_url) override;
+ bool DoesSiteRequireDedicatedProcess(content::BrowserContext *browser_context,
+ const GURL &effective_site_url) override;
+ bool ShouldUseSpareRenderProcessHost(content::BrowserContext *browser_context, const GURL& site_url) override;
+ bool ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(base::StringPiece scheme) override;
#if defined(Q_OS_LINUX)
void GetAdditionalMappedFilesForChildProcess(const base::CommandLine& command_line, int child_process_id, content::PosixFileDescriptorInfo* mappings) override;
@@ -198,24 +208,46 @@ public:
bool HandleExternalProtocol(
const GURL &url,
- content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
+ base::Callback<content::WebContents*(void)> web_contents_getter,
int child_id,
content::NavigationUIData *navigation_data,
bool is_main_frame,
ui::PageTransition page_transition,
bool has_user_gesture,
+ const base::Optional<url::Origin> &initiating_origin,
network::mojom::URLLoaderFactoryPtr *out_factory) override;
- std::vector<std::unique_ptr<content::URLLoaderThrottle>> CreateURLLoaderThrottlesOnIO(
- const network::ResourceRequest &request, content::ResourceContext *resource_context,
- const base::RepeatingCallback<content::WebContents *()> &wc_getter,
- content::NavigationUIData *navigation_ui_data, int frame_tree_node_id) override;
-
- std::vector<std::unique_ptr<content::URLLoaderThrottle>> CreateURLLoaderThrottles(
+ std::vector<std::unique_ptr<blink::URLLoaderThrottle>> CreateURLLoaderThrottles(
const network::ResourceRequest &request, content::BrowserContext *browser_context,
const base::RepeatingCallback<content::WebContents *()> &wc_getter,
content::NavigationUIData *navigation_ui_data, int frame_tree_node_id) override;
+ std::vector<std::unique_ptr<content::NavigationThrottle>> CreateThrottlesForNavigation(
+ content::NavigationHandle *navigation_handle) override;
+
+ bool IsHandledURL(const GURL &url) override;
+
+ bool WillCreateURLLoaderFactory(content::BrowserContext *browser_context,
+ content::RenderFrameHost *frame,
+ int render_process_id,
+ URLLoaderFactoryType type,
+ const url::Origin &request_initiator,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> *factory_receiver,
+ mojo::PendingRemote<network::mojom::TrustedURLLoaderHeaderClient> *header_client,
+ bool *bypass_redirect_checks) override;
+ scoped_refptr<network::SharedURLLoaderFactory> GetSystemSharedURLLoaderFactory() override;
+ network::mojom::NetworkContext *GetSystemNetworkContext() override;
+ void OnNetworkServiceCreated(network::mojom::NetworkService *network_service) override;
+ mojo::Remote<network::mojom::NetworkContext> CreateNetworkContext(content::BrowserContext *context,
+ bool in_memory,
+ const base::FilePath &relative_partition_path) override;
+ std::vector<base::FilePath> GetNetworkContextsParentDirectory() override;
+ void RegisterNonNetworkNavigationURLLoaderFactories(int frame_tree_node_id, NonNetworkURLLoaderFactoryMap *factories) override;
+ void RegisterNonNetworkSubresourceURLLoaderFactories(int render_process_id, int render_frame_id,
+ NonNetworkURLLoaderFactoryMap* factories) override;
+ void RegisterNonNetworkWorkerMainResourceURLLoaderFactories(content::BrowserContext* browser_context,
+ NonNetworkURLLoaderFactoryMap* factories) override;
+
static std::string getUserAgent();
std::string GetUserAgent() override { return getUserAgent(); }
@@ -223,9 +255,7 @@ public:
private:
void InitFrameInterfaces();
- void AddNetworkHintsMessageFilter(int render_process_id, net::URLRequestContext *context);
- std::unique_ptr<content::ResourceDispatcherHostDelegate> m_resourceDispatcherHostDelegate;
scoped_refptr<ShareGroupQtQuick> m_shareGroupQtQuick;
std::unique_ptr<service_manager::BinderRegistry> m_frameInterfaces;
std::unique_ptr<service_manager::BinderRegistryWithArgs<content::RenderFrameHost*>> m_frameInterfacesParameterized;
diff --git a/src/core/content_client_qt.cpp b/src/core/content_client_qt.cpp
index 22f3f548f..6f8fc04f9 100644
--- a/src/core/content_client_qt.cpp
+++ b/src/core/content_client_qt.cpp
@@ -435,11 +435,6 @@ gfx::Image &ContentClientQt::GetNativeImageNamed(int resource_id)
return ui::ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
}
-bool ContentClientQt::IsDataResourceGzipped(int resource_id)
-{
- return ui::ResourceBundle::GetSharedInstance().IsGzipped(resource_id);
-}
-
base::string16 ContentClientQt::GetLocalizedString(int message_id)
{
return l10n_util::GetStringUTF16(message_id);
diff --git a/src/core/content_client_qt.h b/src/core/content_client_qt.h
index 581805a51..a7fc7432a 100644
--- a/src/core/content_client_qt.h
+++ b/src/core/content_client_qt.h
@@ -59,7 +59,6 @@ public:
base::StringPiece GetDataResource(int, ui::ScaleFactor) override;
base::RefCountedMemory* GetDataResourceBytes(int resource_id) override;
gfx::Image &GetNativeImageNamed(int resource_id) override;
- bool IsDataResourceGzipped(int resource_id) override;
base::string16 GetLocalizedString(int message_id) override;
};
diff --git a/src/core/content_main_delegate_qt.cpp b/src/core/content_main_delegate_qt.cpp
index cb23a5287..ff6bf4366 100644
--- a/src/core/content_main_delegate_qt.cpp
+++ b/src/core/content_main_delegate_qt.cpp
@@ -79,36 +79,52 @@ ContentClient *GetContentClient();
namespace QtWebEngineCore {
+namespace {
+
// The logic of this function is based on chrome/common/net/net_resource_provider.cc
// Copyright (c) 2012 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.
-static std::string constructDirHeaderHTML()
-{
- base::DictionaryValue dict;
- dict.SetString("header", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_HEADER));
- dict.SetString("parentDirText", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_PARENT));
- dict.SetString("headerName", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_NAME));
- dict.SetString("headerSize", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_SIZE));
- dict.SetString("headerDateModified",
- l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_DATE_MODIFIED));
- dict.SetString("language", l10n_util::GetLanguage(base::i18n::GetConfiguredLocale()));
- dict.SetString("listingParsingErrorBoxText",
- l10n_util::GetStringFUTF16(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT,
- toString16(QCoreApplication::applicationName())));
- dict.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
- std::string html = webui::GetI18nTemplateHtml(
- ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_DIR_HEADER_HTML),
- &dict);
- return html;
-}
-static base::StringPiece PlatformResourceProvider(int key) {
- if (key == IDR_DIR_HEADER_HTML) {
- static std::string html_data = constructDirHeaderHTML();
- return base::StringPiece(html_data);
+// The net module doesn't have access to this HTML or the strings that need to
+// be localized. The Chrome locale will never change while we're running, so
+// it's safe to have a static string that we always return a pointer into.
+struct LazyDirectoryListerCacher
+{
+ LazyDirectoryListerCacher()
+ {
+ base::DictionaryValue dict;
+ dict.SetString("header", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_HEADER));
+ dict.SetString("parentDirText", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_PARENT));
+ dict.SetString("headerName", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_NAME));
+ dict.SetString("headerSize", l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_SIZE));
+ dict.SetString("headerDateModified",
+ l10n_util::GetStringUTF16(IDS_DIRECTORY_LISTING_DATE_MODIFIED));
+ dict.SetString("language", l10n_util::GetLanguage(base::i18n::GetConfiguredLocale()));
+ dict.SetString("listingParsingErrorBoxText",
+ l10n_util::GetStringFUTF16(IDS_DIRECTORY_LISTING_PARSING_ERROR_BOX_TEXT,
+ toString16(QCoreApplication::applicationName())));
+ dict.SetString("textdirection", base::i18n::IsRTL() ? "rtl" : "ltr");
+ std::string html =
+ webui::GetI18nTemplateHtml(
+ ui::ResourceBundle::GetSharedInstance().DecompressDataResource(IDR_DIR_HEADER_HTML),
+ &dict);
+ html_data = base::RefCountedString::TakeString(&html);
}
- return base::StringPiece();
+
+ scoped_refptr<base::RefCountedMemory> html_data;
+};
+
+} // namespace
+
+static scoped_refptr<base::RefCountedMemory> PlatformResourceProvider(int key)
+{
+ static base::NoDestructor<LazyDirectoryListerCacher> lazy_dir_lister;
+
+ if (IDR_DIR_HEADER_HTML == key)
+ return lazy_dir_lister->html_data;
+
+ return ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(key);
}
// Logging logic is based on chrome/common/logging_chrome.cc:
diff --git a/src/core/content_utility_client_qt.cpp b/src/core/content_utility_client_qt.cpp
index 12a538a07..3582e15a7 100644
--- a/src/core/content_utility_client_qt.cpp
+++ b/src/core/content_utility_client_qt.cpp
@@ -40,6 +40,7 @@
#include "content_utility_client_qt.h"
#include "base/no_destructor.h"
+#include "mojo/public/cpp/bindings/service_factory.h"
#include "services/proxy_resolver/proxy_resolver_factory_impl.h"
namespace QtWebEngineCore {
@@ -50,12 +51,17 @@ ContentUtilityClientQt::ContentUtilityClientQt()
ContentUtilityClientQt::~ContentUtilityClientQt() = default;
-void ContentUtilityClientQt::RunIOThreadService(mojo::GenericPendingReceiver *receiver)
+auto RunProxyResolver(mojo::PendingReceiver<proxy_resolver::mojom::ProxyResolverFactory> receiver)
{
- if (auto factory_receiver = receiver->As<proxy_resolver::mojom::ProxyResolverFactory>()) {
- static base::NoDestructor<proxy_resolver::ProxyResolverFactoryImpl> factory(std::move(factory_receiver));
- return;
- }
+ return std::make_unique<proxy_resolver::ProxyResolverFactoryImpl>(std::move(receiver));
+}
+
+mojo::ServiceFactory *ContentUtilityClientQt::GetIOThreadServiceFactory()
+{
+ static base::NoDestructor<mojo::ServiceFactory> factory {
+ RunProxyResolver,
+ };
+ return factory.get();
}
} // namespace
diff --git a/src/core/content_utility_client_qt.h b/src/core/content_utility_client_qt.h
index 2a9ecff93..fc1d1eb05 100644
--- a/src/core/content_utility_client_qt.h
+++ b/src/core/content_utility_client_qt.h
@@ -53,8 +53,7 @@ public:
~ContentUtilityClientQt() override;
// content::ContentUtilityClient:
- void RunIOThreadService(mojo::GenericPendingReceiver *receiver) override;
-
+ mojo::ServiceFactory *GetIOThreadServiceFactory() override;
};
} // namespace
diff --git a/src/core/core_chromium.pri b/src/core/core_chromium.pri
index 9eab15456..ac118101a 100644
--- a/src/core/core_chromium.pri
+++ b/src/core/core_chromium.pri
@@ -50,7 +50,6 @@ SOURCES = \
clipboard_qt.cpp \
color_chooser_qt.cpp \
color_chooser_controller.cpp \
- command_line_pref_store_qt.cpp \
common/qt_ipc_logging.cpp \
common/qt_messages.cpp \
common/user_script_data.cpp \
@@ -82,17 +81,16 @@ SOURCES = \
net/client_cert_override.cpp \
net/client_cert_store_data.cpp \
net/cookie_monster_delegate_qt.cpp \
- net/custom_protocol_handler.cpp \
- net/network_delegate_qt.cpp \
+ net/custom_url_loader_factory.cpp \
+ net/proxy_config_monitor.cpp \
net/proxy_config_service_qt.cpp \
+ net/proxying_url_loader_factory_qt.cpp \
+ net/proxying_restricted_cookie_manager_qt.cpp \
net/qrc_url_scheme_handler.cpp \
- net/restricted_cookie_manager_qt.cpp \
net/ssl_host_state_delegate_qt.cpp \
- net/url_request_context_getter_qt.cpp \
- net/url_request_custom_job.cpp \
+ net/system_network_context_manager.cpp \
net/url_request_custom_job_delegate.cpp \
net/url_request_custom_job_proxy.cpp \
- net/url_request_notification.cpp \
net/webui_controller_factory_qt.cpp \
ozone/gl_context_qt.cpp \
ozone/gl_ozone_egl_qt.cpp \
@@ -120,11 +118,12 @@ SOURCES = \
renderer/render_view_observer_qt.cpp \
renderer/render_thread_observer_qt.cpp \
renderer/user_resource_controller.cpp \
+ renderer/plugins/loadable_plugin_placeholder_qt.cpp \
+ renderer/plugins/plugin_placeholder_qt.cpp \
renderer_host/render_view_observer_host_qt.cpp \
renderer_host/user_resource_controller_host.cpp \
resource_bundle_qt.cpp \
resource_context_qt.cpp \
- service/service_qt.cpp \
touch_handle_drawable_qt.cpp \
touch_selection_controller_client_qt.cpp \
touch_selection_menu_controller.cpp \
@@ -157,7 +156,6 @@ HEADERS = \
client_cert_select_controller.h \
clipboard_change_observer.h \
clipboard_qt.h \
- command_line_pref_store_qt.h \
color_chooser_qt.h \
color_chooser_controller_p.h \
color_chooser_controller.h \
@@ -193,16 +191,14 @@ HEADERS = \
net/client_cert_override.h \
net/client_cert_store_data.h \
net/cookie_monster_delegate_qt.h \
- net/custom_protocol_handler.h \
- net/network_delegate_qt.h \
+ net/custom_url_loader_factory.h \
+ net/proxying_url_loader_factory_qt.h \
+ net/proxying_restricted_cookie_manager_qt.h \
net/qrc_url_scheme_handler.h \
- net/restricted_cookie_manager_qt.h \
net/ssl_host_state_delegate_qt.h \
- net/url_request_context_getter_qt.h \
- net/url_request_custom_job.h \
+ net/system_network_context_manager.h \
net/url_request_custom_job_delegate.h \
net/url_request_custom_job_proxy.h \
- net/url_request_notification.h \
net/webui_controller_factory_qt.h \
ozone/gl_context_qt.h \
ozone/gl_ozone_egl_qt.h \
@@ -219,6 +215,7 @@ HEADERS = \
profile_adapter_client.h \
profile_qt.h \
profile_io_data_qt.h \
+ proxy_config_monitor.h \
proxy_config_service_qt.h \
quota_permission_context_qt.h \
quota_request_controller.h \
@@ -234,11 +231,12 @@ HEADERS = \
renderer/render_view_observer_qt.h \
renderer/render_thread_observer_qt.h \
renderer/user_resource_controller.h \
+ renderer/plugins/loadable_plugin_placeholder_qt.h \
+ renderer/plugins/plugin_placeholder_qt.h \
renderer_host/render_view_observer_host_qt.h \
renderer_host/user_resource_controller_host.h \
request_controller.h \
resource_context_qt.h \
- service/service_qt.h \
touch_handle_drawable_client.h \
touch_handle_drawable_qt.h \
touch_selection_controller_client_qt.h \
@@ -339,11 +337,11 @@ qtConfig(webengine-extensions) {
extensions/extensions_browser_api_provider_qt.cpp \
extensions/extensions_browser_client_qt.cpp \
extensions/mime_handler_view_guest_delegate_qt.cpp \
+ net/plugin_response_interceptor_url_loader_throttle.cpp \
renderer/extensions/extensions_dispatcher_delegate_qt.cpp \
renderer/extensions/extensions_renderer_client_qt.cpp \
renderer/extensions/renderer_permissions_policy_delegate_qt.cpp \
- renderer/extensions/resource_request_policy_qt.cpp \
- renderer_host/resource_dispatcher_host_delegate_qt.cpp
+ renderer/extensions/resource_request_policy_qt.cpp
HEADERS += \
common/extensions/extensions_api_provider_qt.h \
@@ -356,9 +354,9 @@ qtConfig(webengine-extensions) {
extensions/extensions_browser_api_provider_qt.h \
extensions/extensions_browser_client_qt.h \
extensions/mime_handler_view_guest_delegate_qt.h \
+ net/plugin_response_interceptor_url_loader_throttle.h \
renderer/extensions/extensions_dispatcher_delegate_qt.h \
renderer/extensions/extensions_renderer_client_qt.h \
renderer/extensions/renderer_permissions_policy_delegate_qt.h \
- renderer/extensions/resource_request_policy_qt.h \
- renderer_host/resource_dispatcher_host_delegate_qt.h
+ renderer/extensions/resource_request_policy_qt.h
}
diff --git a/src/core/core_gn_config.pri b/src/core/core_gn_config.pri
index a089eecd0..2b8f2e18f 100644
--- a/src/core/core_gn_config.pri
+++ b/src/core/core_gn_config.pri
@@ -11,6 +11,7 @@ qtConfig (webengine-extensions) {
}
GN_CORE_INCLUDE_DIRS = $$PWD/service
GN_CREATE_PRI = true
+GN_PRECOMPILED_HEADERS = true
QMAKE_INTERNAL_INCLUDED_FILES = $$GN_IMPORTS $$GN_INCLUDES $$GN_FILE
diff --git a/src/core/devtools_frontend_qt.cpp b/src/core/devtools_frontend_qt.cpp
index 1dcbd1e9d..8d325eca6 100644
--- a/src/core/devtools_frontend_qt.cpp
+++ b/src/core/devtools_frontend_qt.cpp
@@ -130,7 +130,7 @@ public:
private:
void OnResponseStarted(const GURL &final_url,
- const network::ResourceResponseHead &response_head)
+ const network::mojom::URLResponseHead &response_head)
{
response_headers_ = response_head.headers;
}
diff --git a/src/core/download_manager_delegate_qt.cpp b/src/core/download_manager_delegate_qt.cpp
index 7049b8273..fe7f7c57b 100644
--- a/src/core/download_manager_delegate_qt.cpp
+++ b/src/core/download_manager_delegate_qt.cpp
@@ -229,14 +229,12 @@ bool DownloadManagerDelegateQt::DetermineDownloadTarget(download::DownloadItem*
}
void DownloadManagerDelegateQt::GetSaveDir(content::BrowserContext* browser_context,
- base::FilePath* website_save_dir,
- base::FilePath* download_save_dir,
- bool* skip_dir_check)
+ base::FilePath* website_save_dir,
+ base::FilePath* download_save_dir)
{
static base::FilePath::StringType save_dir = toFilePathString(QStandardPaths::writableLocation(QStandardPaths::DownloadLocation));
*website_save_dir = base::FilePath(save_dir);
*download_save_dir = base::FilePath(save_dir);
- *skip_dir_check = true;
}
void DownloadManagerDelegateQt::ChooseSavePath(content::WebContents *web_contents,
diff --git a/src/core/download_manager_delegate_qt.h b/src/core/download_manager_delegate_qt.h
index 6acfa42ce..4634790cc 100644
--- a/src/core/download_manager_delegate_qt.h
+++ b/src/core/download_manager_delegate_qt.h
@@ -77,8 +77,7 @@ public:
void GetSaveDir(content::BrowserContext* browser_context,
base::FilePath* website_save_dir,
- base::FilePath* download_save_dir,
- bool* skip_dir_check) override;
+ base::FilePath* download_save_dir) override;
void ChooseSavePath(content::WebContents *web_contents,
const base::FilePath &suggested_path,
const base::FilePath::StringType &default_extension,
diff --git a/src/core/extensions/extension_system_qt.cpp b/src/core/extensions/extension_system_qt.cpp
index fbe98099c..a66051fbd 100644
--- a/src/core/extensions/extension_system_qt.cpp
+++ b/src/core/extensions/extension_system_qt.cpp
@@ -136,7 +136,8 @@ public:
// This should return what verification mode is appropriate for the given
// extension, if any.
- bool ShouldBeVerified(const Extension &extension) override { return false; }
+ VerifierSourceType GetVerifierSourceType(const Extension &extension) override
+ { return VerifierSourceType::NONE; }
// Should return the public key to use for validating signatures via the two
// out parameters.
@@ -174,7 +175,7 @@ void ExtensionSystemQt::LoadExtension(std::string extension_id, std::unique_ptr<
if (!extension.get())
LOG(ERROR) << error;
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
base::Bind(&InfoMap::AddExtension,
base::Unretained(info_map()),
base::RetainedRef(extension),
@@ -411,7 +412,7 @@ void ExtensionSystemQt::RegisterExtensionWithRequestContexts(const Extension *ex
bool incognito_enabled = false;
bool notifications_disabled = false;
- base::PostTaskWithTraitsAndReply(
+ base::PostTaskAndReply(
FROM_HERE, {BrowserThread::IO},
base::Bind(&InfoMap::AddExtension, info_map(),
base::RetainedRef(extension), install_time, incognito_enabled,
@@ -422,7 +423,7 @@ void ExtensionSystemQt::RegisterExtensionWithRequestContexts(const Extension *ex
void ExtensionSystemQt::UnregisterExtensionWithRequestContexts(const std::string &extension_id,
const UnloadedExtensionReason reason)
{
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, {BrowserThread::IO},
base::Bind(&InfoMap::RemoveExtension, info_map(), extension_id, reason));
}
diff --git a/src/core/extensions/extension_web_contents_observer_qt.cpp b/src/core/extensions/extension_web_contents_observer_qt.cpp
index 365f04e46..5b1514bb4 100644
--- a/src/core/extensions/extension_web_contents_observer_qt.cpp
+++ b/src/core/extensions/extension_web_contents_observer_qt.cpp
@@ -70,42 +70,6 @@ void ExtensionWebContentsObserverQt::CreateForWebContents(content::WebContents *
FromWebContents(web_contents)->Initialize();
}
-std::string ExtensionWebContentsObserverQt::GetExtensionIdFromFrame(content::RenderFrameHost *render_frame_host) const
-{
- const GURL &site = render_frame_host->GetSiteInstance()->GetSiteURL();
- if (!site.SchemeIs(kExtensionScheme))
- return std::string();
-
- return site.host();
-}
-
-const Extension *ExtensionWebContentsObserverQt::GetExtensionFromFrame(content::RenderFrameHost *render_frame_host, bool verify_url) const
-{
- std::string extension_id = GetExtensionIdFromFrame(render_frame_host);
- if (extension_id.empty())
- return nullptr;
-
- content::BrowserContext *browser_context =
- render_frame_host->GetProcess()->GetBrowserContext();
- const Extension *extension = ExtensionRegistry::Get(browser_context)
- ->enabled_extensions()
- .GetByID(extension_id);
- if (!extension)
- return nullptr;
-
- if (verify_url) {
- const url::Origin &origin(render_frame_host->GetLastCommittedOrigin());
- // Without site isolation, this check is needed to eliminate non-extension
- // schemes. With site isolation, this is still needed to exclude sandboxed
- // extension frames with a unique origin.
- const GURL site_url(render_frame_host->GetSiteInstance()->GetSiteURL());
- if (origin.opaque() || site_url != content::SiteInstance::GetSiteForURL(browser_context, origin.GetURL()))
- return nullptr;
- }
-
- return extension;
-}
-
void ExtensionWebContentsObserverQt::RenderFrameCreated(content::RenderFrameHost *render_frame_host)
{
ExtensionWebContentsObserver::RenderFrameCreated(render_frame_host);
diff --git a/src/core/extensions/extension_web_contents_observer_qt.h b/src/core/extensions/extension_web_contents_observer_qt.h
index a528b3856..658966b31 100644
--- a/src/core/extensions/extension_web_contents_observer_qt.h
+++ b/src/core/extensions/extension_web_contents_observer_qt.h
@@ -59,9 +59,6 @@ public:
static void CreateForWebContents(content::WebContents *web_contents);
- std::string GetExtensionIdFromFrame(content::RenderFrameHost *) const;
- const Extension *GetExtensionFromFrame(content::RenderFrameHost *, bool) const;
-
// content::WebContentsObserver overrides.
void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override;
diff --git a/src/core/extensions/extensions_browser_client_qt.cpp b/src/core/extensions/extensions_browser_client_qt.cpp
index 59c15d2f5..a91127192 100644
--- a/src/core/extensions/extensions_browser_client_qt.cpp
+++ b/src/core/extensions/extensions_browser_client_qt.cpp
@@ -66,10 +66,13 @@
#include "extensions/browser/mojo/interface_registration.h"
#include "extensions/browser/url_request_util.h"
#include "extensions/common/file_util.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
#include "net/base/completion_once_callback.h"
#include "net/base/mime_util.h"
#include "net/url_request/url_request_simple_job.h"
+#include "services/network/public/cpp/resource_response.h"
#include "services/network/public/mojom/url_loader.mojom.h"
+#include "third_party/zlib/google/compression_utils.h"
#include "ui/base/resource/resource_bundle.h"
#include "component_extension_resource_manager_qt.h"
@@ -102,67 +105,160 @@ void DetermineCharset(const std::string &mime_type,
}
}
-// A request for an extension resource in a Chrome .pak file. These are used
-// by component extensions.
-class URLRequestResourceBundleJob : public net::URLRequestSimpleJob
+scoped_refptr<base::RefCountedMemory> GetResource(int resource_id, const std::string &extension_id)
+{
+ const ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance();
+ scoped_refptr<base::RefCountedMemory> bytes = rb.LoadDataResourceBytes(resource_id);
+ auto *replacements = extensions::ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()
+ ? extensions::ExtensionsBrowserClient::Get()->GetComponentExtensionResourceManager()->GetTemplateReplacementsForExtension(
+ extension_id)
+ : nullptr;
+
+ bool is_gzipped = rb.IsGzipped(resource_id);
+ if (!bytes->size() || (!replacements && !is_gzipped)) {
+ return bytes;
+ }
+
+ base::StringPiece input(reinterpret_cast<const char *>(bytes->front()), bytes->size());
+
+ std::string temp_str;
+
+ base::StringPiece source = input;
+ if (is_gzipped) {
+ temp_str.resize(compression::GetUncompressedSize(input));
+ source = temp_str;
+ CHECK(compression::GzipUncompress(input, source));
+ }
+
+ if (replacements) {
+ temp_str = ui::ReplaceTemplateExpressions(source, *replacements);
+ }
+
+ DCHECK(!temp_str.empty());
+
+ return base::RefCountedString::TakeString(&temp_str);
+}
+
+// Loads an extension resource in a Chrome .pak file. These are used by
+// component extensions.
+class ResourceBundleFileLoader : public network::mojom::URLLoader
{
public:
- URLRequestResourceBundleJob(net::URLRequest *request, net::NetworkDelegate *network_delegate,
- const base::FilePath &filename, int resource_id,
- const std::string &content_security_policy, bool send_cors_header)
- : net::URLRequestSimpleJob(request, network_delegate)
- , filename_(filename)
- , resource_id_(resource_id)
- , weak_factory_(this)
+ static void CreateAndStart(const network::ResourceRequest &request, network::mojom::URLLoaderRequest loader,
+ network::mojom::URLLoaderClientPtrInfo client_info, const base::FilePath &filename,
+ int resource_id, const std::string &content_security_policy, bool send_cors_header)
+ {
+ // Owns itself. Will live as long as its URLLoader and URLLoaderClientPtr
+ // bindings are alive - essentially until either the client gives up or all
+ // file data has been sent to it.
+ auto *bundle_loader = new ResourceBundleFileLoader(content_security_policy, send_cors_header);
+ bundle_loader->Start(request, std::move(loader), std::move(client_info), filename, resource_id);
+ }
+
+ // mojom::URLLoader implementation:
+ void FollowRedirect(const std::vector<std::string> &removed_headers,
+ const net::HttpRequestHeaders &modified_headers, const base::Optional<GURL> &new_url) override
{
- // Leave cache headers out of resource bundle requests.
- response_info_.headers = extensions::BuildHttpHeaders(content_security_policy, send_cors_header, base::Time());
+ NOTREACHED() << "No redirects for local file loads.";
}
- int GetRefCountedData(std::string *mime_type, std::string *charset, scoped_refptr<base::RefCountedMemory> *data,
- net::CompletionOnceCallback callback) const override
+ // Current implementation reads all resource data at start of resource
+ // load, so priority, and pausing is not currently implemented.
+ void SetPriority(net::RequestPriority priority, int32_t intra_priority_value) override {}
+ void PauseReadingBodyFromNet() override {}
+ void ResumeReadingBodyFromNet() override {}
+
+private:
+ ResourceBundleFileLoader(const std::string &content_security_policy, bool send_cors_header) : binding_(this)
{
- const ui::ResourceBundle &rb = ui::ResourceBundle::GetSharedInstance();
- *data = rb.LoadDataResourceBytes(resource_id_);
+ response_headers_ = extensions::BuildHttpHeaders(content_security_policy, send_cors_header, base::Time());
+ }
+ ~ResourceBundleFileLoader() override = default;
- // Add the Content-Length header now that we know the resource length.
- response_info_.headers->AddHeader(base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentLength,
- base::NumberToString((*data)->size()).c_str()));
+ void Start(const network::ResourceRequest &request, network::mojom::URLLoaderRequest loader,
+ network::mojom::URLLoaderClientPtrInfo client_info, const base::FilePath &filename, int resource_id)
+ {
+ client_.Bind(std::move(client_info));
+ binding_.Bind(std::move(loader));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&ResourceBundleFileLoader::OnBindingError, base::Unretained(this)));
+ client_.set_connection_error_handler(
+ base::BindOnce(&ResourceBundleFileLoader::OnConnectionError, base::Unretained(this)));
+ auto data = GetResource(resource_id, request.url.host());
std::string *read_mime_type = new std::string;
- base::PostTaskWithTraitsAndReplyWithResult(
- FROM_HERE, { base::MayBlock() },
- base::BindOnce(&net::GetMimeTypeFromFile, filename_, base::Unretained(read_mime_type)),
- base::BindOnce(&URLRequestResourceBundleJob::OnMimeTypeRead, weak_factory_.GetWeakPtr(), mime_type,
- charset, *data, base::Owned(read_mime_type), std::move(callback)));
-
- return net::ERR_IO_PENDING;
+ base::PostTaskAndReplyWithResult(
+ FROM_HERE, { base::ThreadPool(), base::MayBlock() },
+ base::BindOnce(&net::GetMimeTypeFromFile, filename, base::Unretained(read_mime_type)),
+ base::BindOnce(&ResourceBundleFileLoader::OnMimeTypeRead, weak_factory_.GetWeakPtr(), std::move(data),
+ base::Owned(read_mime_type)));
}
- void GetResponseInfo(net::HttpResponseInfo *info) override { *info = response_info_; }
+ void OnMimeTypeRead(scoped_refptr<base::RefCountedMemory> data, std::string *read_mime_type, bool read_result)
+ {
+ network::ResourceResponseHead head;
+ head.request_start = base::TimeTicks::Now();
+ head.response_start = base::TimeTicks::Now();
+ head.content_length = data->size();
+ head.mime_type = *read_mime_type;
+ DetermineCharset(head.mime_type, data.get(), &head.charset);
+ mojo::DataPipe pipe(data->size());
+ if (!pipe.consumer_handle.is_valid()) {
+ client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
+ client_.reset();
+ MaybeDeleteSelf();
+ return;
+ }
+ head.headers = response_headers_;
+ head.headers->AddHeader(base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentLength,
+ base::NumberToString(head.content_length).c_str()));
+ if (!head.mime_type.empty()) {
+ head.headers->AddHeader(
+ base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType, head.mime_type.c_str()));
+ }
+ client_->OnReceiveResponse(head);
+ client_->OnStartLoadingResponseBody(std::move(pipe.consumer_handle));
-private:
- ~URLRequestResourceBundleJob() override {}
+ uint32_t write_size = data->size();
+ MojoResult result = pipe.producer_handle->WriteData(data->front(), &write_size, MOJO_WRITE_DATA_FLAG_NONE);
+ OnFileWritten(result);
+ }
- void OnMimeTypeRead(std::string *out_mime_type, std::string *charset, scoped_refptr<base::RefCountedMemory> data,
- std::string *read_mime_type, net::CompletionOnceCallback callback, bool read_result)
+ void OnConnectionError()
{
- response_info_.headers->AddHeader(
- base::StringPrintf("%s: %s", net::HttpRequestHeaders::kContentType, read_mime_type->c_str()));
- *out_mime_type = *read_mime_type;
- DetermineCharset(*read_mime_type, data.get(), charset);
- int result = read_result ? net::OK : net::ERR_INVALID_URL;
- std::move(callback).Run(result);
+ client_.reset();
+ MaybeDeleteSelf();
}
- // We need the filename of the resource to determine the mime type.
- base::FilePath filename_;
+ void OnBindingError()
+ {
+ binding_.Close();
+ MaybeDeleteSelf();
+ }
+
+ void MaybeDeleteSelf()
+ {
+ if (!binding_.is_bound() && !client_.is_bound())
+ delete this;
+ }
- // The resource to load.
- int resource_id_;
+ void OnFileWritten(MojoResult result)
+ {
+ // All the data has been written now. The consumer will be notified that
+ // there will be no more data to read from now.
+ if (result == MOJO_RESULT_OK)
+ client_->OnComplete(network::URLLoaderCompletionStatus(net::OK));
+ else
+ client_->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
+ client_.reset();
+ MaybeDeleteSelf();
+ }
- net::HttpResponseInfo response_info_;
+ mojo::Binding<network::mojom::URLLoader> binding_;
+ network::mojom::URLLoaderClientPtr client_;
+ scoped_refptr<net::HttpResponseHeaders> response_headers_;
+ base::WeakPtrFactory<ResourceBundleFileLoader> weak_factory_{ this };
- mutable base::WeakPtrFactory<URLRequestResourceBundleJob> weak_factory_;
+ DISALLOW_COPY_AND_ASSIGN(ResourceBundleFileLoader);
};
} // namespace
@@ -235,38 +331,6 @@ bool ExtensionsBrowserClientQt::CanExtensionCrossIncognito(const Extension *exte
return false;
}
-net::URLRequestJob *ExtensionsBrowserClientQt::MaybeCreateResourceBundleRequestJob(net::URLRequest *request,
- net::NetworkDelegate *network_delegate,
- const base::FilePath &directory_path,
- const std::string &content_security_policy,
- bool send_cors_header)
-{
- base::FilePath resources_path;
- base::FilePath relative_path;
- // Try to load extension resources from chrome resource file if
- // directory_path is a descendant of resources_path. resources_path
- // corresponds to src/chrome/browser/resources in source tree.
- if (base::PathService::Get(base::DIR_QT_LIBRARY_DATA, &resources_path) &&
- // Since component extension resources are included in
- // component_extension_resources.pak file in resources_path, calculate
- // extension relative path against resources_path.
- resources_path.AppendRelativePath(directory_path, &relative_path)) {
- base::FilePath request_path = extensions::file_util::ExtensionURLToRelativeFilePath(request->url());
- int resource_id = 0;
- if (GetComponentExtensionResourceManager()->IsComponentExtensionResource(directory_path, request_path, &resource_id)) {
- relative_path = relative_path.Append(request_path);
- relative_path = relative_path.NormalizePathSeparators();
- return new URLRequestResourceBundleJob(request,
- network_delegate,
- relative_path,
- resource_id,
- content_security_policy,
- send_cors_header);
- }
- }
- return nullptr;
-}
-
// Return the resource relative path and id for the given request.
base::FilePath ExtensionsBrowserClientQt::GetBundleResourcePath(const network::ResourceRequest &request,
const base::FilePath &extension_resources_path,
@@ -307,7 +371,8 @@ void ExtensionsBrowserClientQt::LoadResourceFromResourceBundle(const network::Re
network::mojom::URLLoaderClientPtr client,
bool send_cors_header)
{
- NOTIMPLEMENTED();
+ ResourceBundleFileLoader::CreateAndStart(request, std::move(loader), client.PassInterface(), resource_relative_path,
+ resource_id, content_security_policy, send_cors_header);
}
@@ -409,7 +474,7 @@ const ComponentExtensionResourceManager *ExtensionsBrowserClientQt::GetComponent
void ExtensionsBrowserClientQt::BroadcastEventToRenderers(events::HistogramValue histogram_value,
const std::string &event_name,
- std::unique_ptr<base::ListValue> args)
+ std::unique_ptr<base::ListValue> args, bool dispatch_to_off_the_record_profiles)
{
NOTIMPLEMENTED();
// TODO : do the event routing
diff --git a/src/core/extensions/extensions_browser_client_qt.h b/src/core/extensions/extensions_browser_client_qt.h
index 41cb2ce20..1a90bae95 100644
--- a/src/core/extensions/extensions_browser_client_qt.h
+++ b/src/core/extensions/extensions_browser_client_qt.h
@@ -73,11 +73,6 @@ public:
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;
- net::URLRequestJob *MaybeCreateResourceBundleRequestJob(net::URLRequest *request,
- net::NetworkDelegate *network_delegate,
- const base::FilePath &directory_path,
- const std::string &content_security_policy,
- bool send_cors_header) override;
bool AllowCrossRendererResourceLoad(const GURL &url,
content::ResourceType resource_type,
ui::PageTransition page_transition,
@@ -105,7 +100,8 @@ public:
GetComponentExtensionResourceManager() override;
void BroadcastEventToRenderers(events::HistogramValue histogram_value,
const std::string &event_name,
- std::unique_ptr<base::ListValue> args) override;
+ std::unique_ptr<base::ListValue> args,
+ bool dispatch_to_off_the_record_profiles) override;
ExtensionCache *GetExtensionCache() override;
bool IsBackgroundUpdateAllowed() override;
bool IsMinBrowserVersionSupported(const std::string &min_version) override;
diff --git a/src/core/file_picker_controller.cpp b/src/core/file_picker_controller.cpp
index 62e02e126..3c81a977c 100644
--- a/src/core/file_picker_controller.cpp
+++ b/src/core/file_picker_controller.cpp
@@ -100,10 +100,19 @@ void FilePickerController::accepted(const QStringList &files)
void FilePickerController::accepted(const QVariant &files)
{
- if (!files.canConvert(QVariant::StringList))
+ QStringList stringList;
+
+ if (files.canConvert(QVariant::StringList)) {
+ stringList = files.toStringList();
+ } else if (files.canConvert<QList<QUrl> >()) {
+ const QList<QUrl> urls = files.value<QList<QUrl>>();
+ for (const QUrl &url : urls)
+ stringList.append(url.toLocalFile());
+ } else {
qWarning("An unhandled type '%s' was provided in FilePickerController::accepted(QVariant)", files.typeName());
+ }
- accepted(files.toStringList());
+ accepted(stringList);
}
void FilePickerController::rejected()
diff --git a/src/core/login_delegate_qt.cpp b/src/core/login_delegate_qt.cpp
index f63252112..1b9c22191 100644
--- a/src/core/login_delegate_qt.cpp
+++ b/src/core/login_delegate_qt.cpp
@@ -48,9 +48,9 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/resource_request_info.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"
@@ -82,7 +82,7 @@ LoginDelegateQt::LoginDelegateQt(const net::AuthChallengeInfo &authInfo,
, m_auth_required_callback(std::move(auth_required_callback))
, m_weakFactory(this)
{
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, { content::BrowserThread::UI },
base::BindOnce(&LoginDelegateQt::triggerDialog, m_weakFactory.GetWeakPtr()));
}
@@ -153,7 +153,9 @@ void LoginDelegateQt::sendAuthToRequester(bool success, const QString &user, con
std::move(m_auth_required_callback).Run(base::nullopt);
}
- destroy();
+ // With network service the auth callback has already deleted us.
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ destroy();
}
void LoginDelegateQt::destroy()
diff --git a/src/core/login_delegate_qt.h b/src/core/login_delegate_qt.h
index 20f302988..116fe3c56 100644
--- a/src/core/login_delegate_qt.h
+++ b/src/core/login_delegate_qt.h
@@ -42,7 +42,6 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/login_delegate.h"
-#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents_observer.h"
#include "url/gurl.h"
diff --git a/src/core/media_capture_devices_dispatcher.cpp b/src/core/media_capture_devices_dispatcher.cpp
index 7bf499917..2293c424a 100644
--- a/src/core/media_capture_devices_dispatcher.cpp
+++ b/src/core/media_capture_devices_dispatcher.cpp
@@ -280,9 +280,9 @@ void MediaCaptureDevicesDispatcher::handleMediaAccessPermissionResponse(content:
// Post a task to process next queued request. It has to be done
// asynchronously to make sure that calling infobar is not destroyed until
// after this function returns.
- base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
- base::BindOnce(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest,
- base::Unretained(this), webContents));
+ base::PostTask(FROM_HERE, {BrowserThread::UI},
+ base::BindOnce(&MediaCaptureDevicesDispatcher::ProcessQueuedAccessRequest,
+ base::Unretained(this), webContents));
}
if (devices.empty())
@@ -368,7 +368,7 @@ void MediaCaptureDevicesDispatcher::processDesktopCaptureAccessRequest(content::
// Resolve DesktopMediaID for the specified device id.
mediaId = content::DesktopStreamsRegistry::GetInstance()->RequestMediaForStreamId(
request.requested_video_device_id, main_frame->GetProcess()->GetID(),
- main_frame->GetRoutingID(), request.security_origin,
+ main_frame->GetRoutingID(), url::Origin::Create(request.security_origin),
&originalExtensionName, content::kRegistryStreamTypeDesktop);
}
@@ -444,10 +444,10 @@ void MediaCaptureDevicesDispatcher::getDefaultDevices(const std::string &audioDe
void MediaCaptureDevicesDispatcher::OnMediaRequestStateChanged(int render_process_id, int render_frame_id, int page_request_id, const GURL &security_origin, blink::mojom::MediaStreamType stream_type, content::MediaRequestState state)
{
DCHECK_CURRENTLY_ON(BrowserThread::IO);
- base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
- base::BindOnce(&MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread,
- base::Unretained(this), render_process_id, render_frame_id,
- page_request_id, security_origin, stream_type, state));
+ base::PostTask(FROM_HERE, {BrowserThread::UI},
+ base::BindOnce(&MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread,
+ base::Unretained(this), render_process_id, render_frame_id,
+ page_request_id, security_origin, stream_type, state));
}
void MediaCaptureDevicesDispatcher::updateMediaRequestStateOnUIThread(int render_process_id,
diff --git a/src/core/net/client_cert_override.cpp b/src/core/net/client_cert_override.cpp
index afb7ab5af..f33515f63 100644
--- a/src/core/net/client_cert_override.cpp
+++ b/src/core/net/client_cert_override.cpp
@@ -142,7 +142,7 @@ void ClientCertOverrideStore::GetClientCerts(const net::SSLCertRequestInfo &cert
{
#if QT_CONFIG(ssl)
// Access the user-provided data from the UI thread, but return on whatever thread this is.
- if (base::PostTaskWithTraitsAndReplyWithResult(
+ if (base::PostTaskAndReplyWithResult(
FROM_HERE, { content::BrowserThread::UI },
base::BindOnce(&ClientCertOverrideStore::GetClientCertsOnUIThread,
base::Unretained(this), std::cref(cert_request_info)),
diff --git a/src/core/net/cookie_monster_delegate_qt.cpp b/src/core/net/cookie_monster_delegate_qt.cpp
index dad9a8db5..cf114406b 100644
--- a/src/core/net/cookie_monster_delegate_qt.cpp
+++ b/src/core/net/cookie_monster_delegate_qt.cpp
@@ -44,7 +44,9 @@
#include "base/task/post_task.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/binding.h"
#include "net/cookies/cookie_util.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
#include "api/qwebenginecookiestore.h"
#include "api/qwebenginecookiestore_p.h"
@@ -52,6 +54,24 @@
namespace QtWebEngineCore {
+class CookieChangeListener : public network::mojom::CookieChangeListener
+{
+public:
+ CookieChangeListener(CookieMonsterDelegateQt *delegate) : m_delegate(delegate) { }
+ ~CookieChangeListener() override = default;
+
+ // network::mojom::CookieChangeListener:
+ void OnCookieChange(const net::CookieChangeInfo &change) override
+ {
+ m_delegate->OnCookieChanged(change);
+ }
+
+private:
+ CookieMonsterDelegateQt *m_delegate;
+
+ DISALLOW_COPY_AND_ASSIGN(CookieChangeListener);
+};
+
static GURL sourceUrlForCookie(const QNetworkCookie &cookie)
{
QString urlFragment = QStringLiteral("%1%2").arg(cookie.domain()).arg(cookie.path());
@@ -59,44 +79,34 @@ static GURL sourceUrlForCookie(const QNetworkCookie &cookie)
}
CookieMonsterDelegateQt::CookieMonsterDelegateQt()
- : m_client(0)
- , m_cookieMonster(nullptr)
+ : m_client(nullptr)
+ , m_listener(new CookieChangeListener(this))
+ , m_receiver(m_listener.get())
{
}
CookieMonsterDelegateQt::~CookieMonsterDelegateQt()
{
-
}
void CookieMonsterDelegateQt::AddStore(net::CookieStore *store)
{
std::unique_ptr<net::CookieChangeSubscription> sub = store->GetChangeDispatcher().AddCallbackForAllChanges(
- base::Bind(&CookieMonsterDelegateQt::OnCookieChanged,
- // this object's destruction will deregister the subscription.
- base::Unretained(this)));
+ base::BindRepeating(&CookieMonsterDelegateQt::OnCookieChanged,
+ // this object's destruction will deregister the subscription.
+ base::Unretained(this)));
m_subscriptions.push_back(std::move(sub));
}
bool CookieMonsterDelegateQt::hasCookieMonster()
{
- return m_cookieMonster;
+ return m_mojoCookieManager.is_bound();
}
void CookieMonsterDelegateQt::getAllCookies(quint64 callbackId)
{
- net::CookieMonster::GetCookieListCallback callback =
- base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread, this, callbackId);
-
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesOnIOThread, this, std::move(callback)));
-}
-
-void CookieMonsterDelegateQt::GetAllCookiesOnIOThread(net::CookieMonster::GetCookieListCallback callback)
-{
- if (m_cookieMonster)
- m_cookieMonster->GetAllCookiesAsync(std::move(callback));
+ m_mojoCookieManager->GetAllCookies(base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId));
}
void CookieMonsterDelegateQt::setCookie(quint64 callbackId, const QNetworkCookie &cookie, const QUrl &origin)
@@ -105,24 +115,18 @@ void CookieMonsterDelegateQt::setCookie(quint64 callbackId, const QNetworkCookie
Q_ASSERT(m_client);
net::CookieStore::SetCookiesCallback callback;
- if (callbackId != CallbackDirectory::NoCallbackId)
- callback = base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnIOThread, this, callbackId);
GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin);
+ std::string cookie_line = cookie.toRawForm().toStdString();
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&CookieMonsterDelegateQt::SetCookieOnIOThread, this,
- gurl, cookie.toRawForm().toStdString(), std::move(callback)));
-}
-
-void CookieMonsterDelegateQt::SetCookieOnIOThread(const GURL &url, const std::string &cookie_line,
- net::CookieMonster::SetCookiesCallback callback)
-{
+ if (callbackId != CallbackDirectory::NoCallbackId)
+ callback = base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId);
+ net::CanonicalCookie::CookieInclusionStatus inclusion;
+ auto canonCookie = net::CanonicalCookie::Create(gurl, cookie_line, base::Time::Now(), base::nullopt, &inclusion);
net::CookieOptions options;
- options.set_include_httponly();
-
- if (m_cookieMonster)
- m_cookieMonster->SetCookieWithOptionsAsync(url, cookie_line, options, std::move(callback));
+ if (!inclusion.HasExclusionReason(net::CanonicalCookie::CookieInclusionStatus::EXCLUDE_HTTP_ONLY))
+ options.set_include_httponly();
+ m_mojoCookieManager->SetCanonicalCookie(*canonCookie.get(), gurl.scheme(), options, std::move(callback));
}
void CookieMonsterDelegateQt::deleteCookie(const QNetworkCookie &cookie, const QUrl &origin)
@@ -131,53 +135,23 @@ void CookieMonsterDelegateQt::deleteCookie(const QNetworkCookie &cookie, const Q
Q_ASSERT(m_client);
GURL gurl = origin.isEmpty() ? sourceUrlForCookie(cookie) : toGurl(origin);
-
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&CookieMonsterDelegateQt::DeleteCookieOnIOThread, this,
- gurl, cookie.name().toStdString()));
-}
-
-void CookieMonsterDelegateQt::DeleteCookieOnIOThread(const GURL &url, const std::string &cookie_name)
-{
- if (m_cookieMonster) {
- net::CookieMonster::GetCookieListCallback callback =
- base::BindOnce(&CookieMonsterDelegateQt::GetCookiesToDeleteCallback, this, cookie_name);
- m_cookieMonster->GetAllCookiesForURLAsync(url, std::move(callback));
- }
-}
-
-void CookieMonsterDelegateQt::GetCookiesToDeleteCallback(const std::string &cookie_name, const net::CookieList &cookies,
- const net::CookieStatusList &statusList)
-{
- Q_UNUSED(statusList);
- if (!m_cookieMonster)
- return;
-
- net::CookieList cookiesToDelete;
- for (auto cookie : cookies) {
- if (cookie.Name() == cookie_name)
- cookiesToDelete.push_back(cookie);
- }
- for (auto cookie : cookiesToDelete)
- m_cookieMonster->DeleteCanonicalCookieAsync(cookie, base::DoNothing());
+ std::string cookie_name = cookie.name().toStdString();
+ auto filter = network::mojom::CookieDeletionFilter::New();
+ filter->url = gurl;
+ filter->cookie_name = cookie_name;
+ m_mojoCookieManager->DeleteCookies(std::move(filter), network::mojom::CookieManager::DeleteCookiesCallback());
}
-
void CookieMonsterDelegateQt::deleteSessionCookies(quint64 callbackId)
{
Q_ASSERT(hasCookieMonster());
Q_ASSERT(m_client);
- net::CookieMonster::DeleteCallback callback =
- base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread, this, callbackId);
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread, this, std::move(callback)));
-}
-
-void CookieMonsterDelegateQt::DeleteSessionCookiesOnIOThread(net::CookieMonster::DeleteCallback callback)
-{
- if (m_cookieMonster)
- m_cookieMonster->DeleteSessionCookiesAsync(std::move(callback));
+ network::mojom::CookieManager::DeleteCookiesCallback callback =
+ base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId);
+ auto filter = network::mojom::CookieDeletionFilter::New();
+ filter->session_control = network::mojom::CookieDeletionSessionControl::SESSION_COOKIES;
+ m_mojoCookieManager->DeleteCookies(std::move(filter), std::move(callback));
}
void CookieMonsterDelegateQt::deleteAllCookies(quint64 callbackId)
@@ -185,36 +159,32 @@ void CookieMonsterDelegateQt::deleteAllCookies(quint64 callbackId)
Q_ASSERT(hasCookieMonster());
Q_ASSERT(m_client);
- net::CookieMonster::DeleteCallback callback =
- base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread, this, callbackId);
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&CookieMonsterDelegateQt::DeleteAllOnIOThread, this, std::move(callback)));
-}
-
-void CookieMonsterDelegateQt::DeleteAllOnIOThread(net::CookieMonster::DeleteCallback callback)
-{
- if (m_cookieMonster)
- m_cookieMonster->DeleteAllAsync(std::move(callback));
+ network::mojom::CookieManager::DeleteCookiesCallback callback =
+ base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId);
+ auto filter = network::mojom::CookieDeletionFilter::New();
+ m_mojoCookieManager->DeleteCookies(std::move(filter), std::move(callback));
}
-void CookieMonsterDelegateQt::setCookieMonster(net::CookieMonster *monster)
+void CookieMonsterDelegateQt::setMojoCookieManager(network::mojom::CookieManagerPtrInfo cookie_manager_info)
{
- if (monster == m_cookieMonster)
- return;
+ if (m_mojoCookieManager.is_bound())
+ unsetMojoCookieManager();
- m_subscriptions.clear();
- if (monster)
- AddStore(monster);
+ Q_ASSERT(!m_mojoCookieManager.is_bound());
+ Q_ASSERT(!m_receiver.is_bound());
- m_cookieMonster = monster;
+ m_mojoCookieManager.Bind(std::move(cookie_manager_info));
- if (!m_client)
- return;
+ m_mojoCookieManager->AddGlobalChangeListener(m_receiver.BindNewPipeAndPassRemote());
- if (monster)
+ if (m_client)
m_client->d_func()->processPendingUserCookies();
- else
- m_client->d_func()->rejectPendingUserCookies();
+}
+
+void CookieMonsterDelegateQt::unsetMojoCookieManager()
+{
+ m_receiver.reset();
+ m_mojoCookieManager.reset();
}
void CookieMonsterDelegateQt::setClient(QWebEngineCookieStore *client)
@@ -246,39 +216,24 @@ bool CookieMonsterDelegateQt::canGetCookies(const QUrl &firstPartyUrl, const QUr
return m_client->d_func()->canAccessCookies(firstPartyUrl, url);
}
-void CookieMonsterDelegateQt::OnCookieChanged(const net::CanonicalCookie &cookie, net::CookieChangeCause cause)
+void CookieMonsterDelegateQt::OnCookieChanged(const net::CookieChangeInfo &change)
{
if (!m_client)
return;
- m_client->d_func()->onCookieChanged(toQt(cookie), cause != net::CookieChangeCause::INSERTED);
+ m_client->d_func()->onCookieChanged(toQt(change.cookie), change.cause != net::CookieChangeCause::INSERTED);
}
-void CookieMonsterDelegateQt::GetAllCookiesCallbackOnIOThread(qint64 callbackId, const net::CookieList &cookies, const net::CookieStatusList &statusList)
+void CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread(qint64 callbackId, const std::vector<net::CanonicalCookie> &cookies)
{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
QByteArray rawCookies;
for (auto &&cookie : cookies)
rawCookies += toQt(cookie).toRawForm() % QByteArrayLiteral("\n");
- base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread, this, callbackId, rawCookies));
-}
-
-void CookieMonsterDelegateQt::SetCookieCallbackOnIOThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status)
-{
- base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&CookieMonsterDelegateQt::SetCookieCallbackOnUIThread, this, callbackId, status));
-}
-
-void CookieMonsterDelegateQt::DeleteCookiesCallbackOnIOThread(qint64 callbackId, uint numCookies)
-{
- base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread, this, callbackId, numCookies));
+ GetAllCookiesResultOnUIThread(callbackId, rawCookies);
}
-void CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread(qint64 callbackId, const QByteArray &cookies)
+void CookieMonsterDelegateQt::GetAllCookiesResultOnUIThread(qint64 callbackId, const QByteArray &cookies)
{
if (m_client)
m_client->d_func()->onGetAllCallbackResult(callbackId, cookies);
@@ -287,8 +242,7 @@ void CookieMonsterDelegateQt::GetAllCookiesCallbackOnUIThread(qint64 callbackId,
void CookieMonsterDelegateQt::SetCookieCallbackOnUIThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status)
{
if (m_client)
- m_client->d_func()->onSetCallbackResult(callbackId,
- status == net::CanonicalCookie::CookieInclusionStatus::INCLUDE);
+ m_client->d_func()->onSetCallbackResult(callbackId, status.IsInclude());
}
void CookieMonsterDelegateQt::DeleteCookiesCallbackOnUIThread(qint64 callbackId, uint numCookies)
diff --git a/src/core/net/cookie_monster_delegate_qt.h b/src/core/net/cookie_monster_delegate_qt.h
index 23b803790..6caaeea94 100644
--- a/src/core/net/cookie_monster_delegate_qt.h
+++ b/src/core/net/cookie_monster_delegate_qt.h
@@ -57,8 +57,22 @@ QT_WARNING_PUSH
// For some reason adding -Wno-unused-parameter to QMAKE_CXXFLAGS has no
// effect with clang, so use a pragma for these dirty chromium headers
QT_WARNING_DISABLE_CLANG("-Wunused-parameter")
+
+// We need to work around Chromium using 'signals' as a variable name in headers:
+#ifdef signals
+#define StAsH_signals signals
+#undef signals
+#endif
#include "base/memory/ref_counted.h"
-#include "net/cookies/cookie_monster.h"
+#include "mojo/public/cpp/bindings/receiver.h"
+#include "net/cookies/cookie_change_dispatcher.h"
+#include "net/cookies/cookie_store.h"
+#include "services/network/public/mojom/cookie_manager.mojom-forward.h"
+#include "services/network/public/mojom/cookie_manager.mojom.h"
+#ifdef StAsH_signals
+#define signals StAsH_signals
+#undef StAsH_signals
+#endif
QT_WARNING_POP
#include <QNetworkCookie>
@@ -68,18 +82,16 @@ QT_FORWARD_DECLARE_CLASS(QWebEngineCookieStore)
namespace QtWebEngineCore {
-// Extends net::CookieMonster::kDefaultCookieableSchemes with qrc, without enabling
-// cookies for the file:// scheme, which is disabled by default in Chromium.
-// Since qrc:// is similar to file:// and there are some unknowns about how
-// to correctly handle file:// cookies, qrc:// should only be used for testing.
-static const char *const kCookieableSchemes[] = { "http", "https", "qrc", "ws", "wss" };
+class CookieMonsterDelegateQtPrivate;
class Q_WEBENGINECORE_PRIVATE_EXPORT CookieMonsterDelegateQt : public base::RefCountedThreadSafe<CookieMonsterDelegateQt>
{
QPointer<QWebEngineCookieStore> m_client;
- net::CookieMonster *m_cookieMonster;
std::vector<std::unique_ptr<net::CookieChangeSubscription>> m_subscriptions;
+ network::mojom::CookieManagerPtr m_mojoCookieManager;
+ std::unique_ptr<network::mojom::CookieChangeListener> m_listener;
+ mojo::Receiver<network::mojom::CookieChangeListener> m_receiver;
public:
CookieMonsterDelegateQt();
~CookieMonsterDelegateQt();
@@ -92,31 +104,19 @@ public:
void deleteSessionCookies(quint64 callbackId);
void deleteAllCookies(quint64 callbackId);
- void setCookieMonster(net::CookieMonster *monster);
void setClient(QWebEngineCookieStore *client);
+ void setMojoCookieManager(network::mojom::CookieManagerPtrInfo cookie_manager_info);
+ void unsetMojoCookieManager();
bool canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url) const;
bool canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) const;
void AddStore(net::CookieStore *store);
- void OnCookieChanged(const net::CanonicalCookie &cookie, net::CookieChangeCause cause);
+ void OnCookieChanged(const net::CookieChangeInfo &change);
private:
- void GetAllCookiesOnIOThread(net::CookieMonster::GetCookieListCallback callback);
- void SetCookieOnIOThread(const GURL &url, const std::string &cookie_line,
- net::CookieMonster::SetCookiesCallback callback);
- void DeleteCookieOnIOThread(const GURL &url, const std::string &cookie_name);
- void DeleteSessionCookiesOnIOThread(net::CookieMonster::DeleteCallback callback);
- void DeleteAllOnIOThread(net::CookieMonster::DeleteCallback callback);
-
- void GetCookiesToDeleteCallback(const std::string &cookie_name, const net::CookieList &cookies,
- const net::CookieStatusList &statusList);
- void GetAllCookiesCallbackOnIOThread(qint64 callbackId, const net::CookieList &cookies,
- const net::CookieStatusList &statusList);
- void SetCookieCallbackOnIOThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status);
- void DeleteCookiesCallbackOnIOThread(qint64 callbackId, uint numCookies);
-
- void GetAllCookiesCallbackOnUIThread(qint64 callbackId, const QByteArray &cookies);
+ void GetAllCookiesCallbackOnUIThread(qint64 callbackId, const std::vector<net::CanonicalCookie> &cookies);
+ void GetAllCookiesResultOnUIThread(qint64 callbackId, const QByteArray &cookies);
void SetCookieCallbackOnUIThread(qint64 callbackId, net::CanonicalCookie::CookieInclusionStatus status);
void DeleteCookiesCallbackOnUIThread(qint64 callbackId, uint numCookies);
};
diff --git a/src/core/net/custom_url_loader_factory.cpp b/src/core/net/custom_url_loader_factory.cpp
new file mode 100644
index 000000000..a96b35696
--- /dev/null
+++ b/src/core/net/custom_url_loader_factory.cpp
@@ -0,0 +1,484 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "custom_url_loader_factory.h"
+
+#include "base/strings/stringprintf.h"
+#include "base/task/post_task.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/system/data_pipe.h"
+#include "mojo/public/cpp/system/simple_watcher.h"
+#include "net/base/net_errors.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+
+#include "api/qwebengineurlscheme.h"
+#include "net/url_request_custom_job_proxy.h"
+#include "profile_adapter.h"
+#include "type_conversion.h"
+
+#include <QtCore/qbytearray.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qfileinfo.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qmimedatabase.h>
+#include <QtCore/qmimedata.h>
+#include <QtCore/qurl.h>
+
+namespace QtWebEngineCore {
+
+namespace {
+
+class CustomURLLoader : public network::mojom::URLLoader
+ , private URLRequestCustomJobProxy::Client
+{
+public:
+ static void CreateAndStart(const network::ResourceRequest &request,
+ network::mojom::URLLoaderRequest loader,
+ network::mojom::URLLoaderClientPtrInfo client_info,
+ QPointer<ProfileAdapter> profileAdapter)
+ {
+ // CustomURLLoader will handle its own life-cycle, and delete when
+ // the client lets go.
+ auto *customUrlLoader = new CustomURLLoader(request, std::move(loader), std::move(client_info), profileAdapter);
+ customUrlLoader->Start();
+ }
+
+ // network::mojom::URLLoader:
+ void FollowRedirect(const std::vector<std::string> &removed_headers,
+ const net::HttpRequestHeaders &modified_headers,
+ const base::Optional<GURL> &new_url) override
+ {
+ // We can be asked for follow our own redirect
+ scoped_refptr<URLRequestCustomJobProxy> proxy = new URLRequestCustomJobProxy(this, m_proxy->m_scheme, m_proxy->m_profileAdapter);
+ m_proxy->m_client = nullptr;
+// m_taskRunner->PostTask(FROM_HERE, base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
+ base::PostTask(FROM_HERE, { content::BrowserThread::UI },
+ base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
+ m_proxy = std::move(proxy);
+ if (new_url)
+ m_request.url = *new_url;
+ else
+ m_request.url = m_redirect;
+ m_redirect = GURL();
+ for (const std::string &header: removed_headers)
+ m_request.headers.RemoveHeader(header);
+ m_request.headers.MergeFrom(modified_headers);
+ Start();
+ }
+ void SetPriority(net::RequestPriority priority, int32_t intra_priority_value) override { }
+ void PauseReadingBodyFromNet() override { }
+ void ResumeReadingBodyFromNet() override { }
+
+private:
+ CustomURLLoader(const network::ResourceRequest &request,
+ network::mojom::URLLoaderRequest loader,
+ network::mojom::URLLoaderClientPtrInfo client_info,
+ QPointer<ProfileAdapter> profileAdapter)
+ // ### We can opt to run the url-loader on the UI thread instead
+ : m_taskRunner(base::CreateSingleThreadTaskRunner({ content::BrowserThread::IO }))
+ , m_proxy(new URLRequestCustomJobProxy(this, request.url.scheme(), profileAdapter))
+ , m_binding(this, std::move(loader))
+ , m_client(std::move(client_info))
+ , m_request(request)
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_binding.set_connection_error_handler(
+ base::BindOnce(&CustomURLLoader::OnConnectionError, m_weakPtrFactory.GetWeakPtr()));
+ m_firstBytePosition = 0;
+ m_device = nullptr;
+ m_error = 0;
+ QWebEngineUrlScheme scheme = QWebEngineUrlScheme::schemeByName(QByteArray::fromStdString(request.url.scheme()));
+ m_corsEnabled = scheme.flags().testFlag(QWebEngineUrlScheme::CorsEnabled);
+ }
+
+ ~CustomURLLoader() override = default;
+
+ void Start()
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_head.request_start = base::TimeTicks::Now();
+
+ if (!m_pipe.consumer_handle.is_valid())
+ return CompleteWithFailure(net::ERR_FAILED);
+
+ std::map<std::string, std::string> headers;
+ net::HttpRequestHeaders::Iterator it(m_request.headers);
+ while (it.GetNext())
+ headers.emplace(it.name(), it.value());
+ if (!m_request.referrer.is_empty())
+ headers.emplace("Referer", m_request.referrer.spec());
+
+ std::string rangeHeader;
+ if (ParseRange(m_request.headers))
+ m_firstBytePosition = m_byteRange.first_byte_position();
+
+// m_taskRunner->PostTask(FROM_HERE,
+ base::PostTask(FROM_HERE, { content::BrowserThread::UI },
+ base::BindOnce(&URLRequestCustomJobProxy::initialize, m_proxy,
+ m_request.url, m_request.method, m_request.request_initiator, std::move(headers)));
+ }
+
+ void CompleteWithFailure(net::Error net_error)
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_client->OnComplete(network::URLLoaderCompletionStatus(net_error));
+ ClearProxyAndClient(false);
+ }
+
+ void OnConnectionError()
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_binding.Close();
+ if (m_client.is_bound())
+ ClearProxyAndClient(false);
+ else
+ delete this;
+ }
+
+ void OnTransferComplete(MojoResult result)
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ if (result == MOJO_RESULT_OK) {
+ network::URLLoaderCompletionStatus status(net::OK);
+ status.encoded_data_length = m_totalBytesRead + m_head.headers->raw_headers().length();
+ status.encoded_body_length = m_totalBytesRead;
+ status.decoded_body_length = m_totalBytesRead;
+ m_client->OnComplete(status);
+ } else {
+ m_client->OnComplete(network::URLLoaderCompletionStatus(net::ERR_FAILED));
+ }
+ ClearProxyAndClient(false /* result == MOJO_RESULT_OK */);
+ }
+
+ void ClearProxyAndClient(bool wait_for_loader_error = false)
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_proxy->m_client = nullptr;
+ m_client.reset();
+ if (m_device && m_device->isOpen())
+ m_device->close();
+ m_device = nullptr;
+// m_taskRunner->PostTask(FROM_HERE, base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
+ base::PostTask(FROM_HERE, { content::BrowserThread::UI },
+ base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
+ if (!wait_for_loader_error || !m_binding.is_bound())
+ delete this;
+ }
+
+ // URLRequestCustomJobProxy::Client:
+ void notifyExpectedContentSize(qint64 size) override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_totalSize = size;
+ if (m_byteRange.IsValid()) {
+ if (!m_byteRange.ComputeBounds(size)) {
+ CompleteWithFailure(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE);
+ } else {
+ m_maxBytesToRead = m_byteRange.last_byte_position() - m_byteRange.first_byte_position() + 1;
+ m_head.content_length = m_maxBytesToRead;
+ }
+ } else {
+ m_head.content_length = size;
+ }
+ }
+ void notifyHeadersComplete() override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ DCHECK(!m_error);
+ m_head.response_start = base::TimeTicks::Now();
+
+ std::string headers;
+ if (!m_redirect.is_empty()) {
+ headers += "HTTP/1.1 303 See Other\n";
+ headers += base::StringPrintf("Location: %s\n", m_redirect.spec().c_str());
+ } else {
+ if (m_byteRange.IsValid() && m_totalSize > 0) {
+ headers += "HTTP/1.1 206 Partial Content\n";
+ headers += net::HttpResponseHeaders::kContentRange;
+ headers += base::StringPrintf(": bytes %lld-%lld/%lld",
+ qlonglong{m_byteRange.first_byte_position()},
+ qlonglong{m_byteRange.last_byte_position()},
+ qlonglong{m_totalSize});
+ headers += "\n";
+ } else {
+ headers += "HTTP/1.1 200 OK\n";
+ }
+ if (m_mimeType.size() > 0) {
+ headers += net::HttpRequestHeaders::kContentType;
+ headers += base::StringPrintf(": %s", m_mimeType.c_str());
+ if (m_charset.size() > 0)
+ headers += base::StringPrintf("; charset=%s", m_charset.c_str());
+ headers += "\n";
+ }
+ }
+ if (m_corsEnabled) {
+ std::string origin;
+ if (m_request.headers.GetHeader("Origin", &origin)) {
+ headers += base::StringPrintf("Access-Control-Allow-Origin: %s\n", origin.c_str());
+ headers += "Access-Control-Allow-Credentials: true\n";
+ }
+ }
+ m_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(net::HttpUtil::AssembleRawHeaders(headers));
+ 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;
+ net::URLRequest::FirstPartyURLPolicy first_party_url_policy =
+ m_request.update_first_party_url_on_redirect ? net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT
+ : net::URLRequest::NEVER_CHANGE_FIRST_PARTY_URL;
+ net::RedirectInfo redirectInfo = net::RedirectInfo::ComputeRedirectInfo(
+ m_request.method, m_request.url,
+ m_request.site_for_cookies,
+ first_party_url_policy, m_request.referrer_policy,
+ m_request.referrer.spec(), net::HTTP_SEE_OTHER,
+ m_redirect, base::nullopt, false /*insecure_scheme_was_upgraded*/);
+ m_client->OnReceiveRedirect(redirectInfo, m_head);
+ // ### should m_request be updated with RedirectInfo? (see FollowRedirect)
+ return;
+ }
+ DCHECK(m_device);
+ m_head.mime_type = m_mimeType;
+ m_head.charset = m_charset;
+ m_client->OnReceiveResponse(m_head);
+ m_client->OnStartLoadingResponseBody(std::move(m_pipe.consumer_handle));
+
+ if (readAvailableData()) // May delete this
+ return;
+
+ m_watcher = std::make_unique<mojo::SimpleWatcher>(
+ FROM_HERE, mojo::SimpleWatcher::ArmingPolicy::AUTOMATIC, m_taskRunner);
+ m_watcher->Watch(m_pipe.producer_handle.get(), MOJO_HANDLE_SIGNAL_WRITABLE,
+ MOJO_WATCH_CONDITION_SATISFIED,
+ base::BindRepeating(&CustomURLLoader::notifyReadyWrite,
+ m_weakPtrFactory.GetWeakPtr()));
+ }
+ void notifyCanceled() override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ OnTransferComplete(MOJO_RESULT_CANCELLED);
+ }
+ void notifyAborted() override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ notifyStartFailure(net::ERR_ABORTED);
+ }
+ void notifyStartFailure(int error) override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ m_head.response_start = base::TimeTicks::Now();
+ std::string headers;
+ switch (error) {
+ case net::ERR_INVALID_URL:
+ headers = "HTTP/1.1 400 Bad Request\n";
+ break;
+ case net::ERR_FILE_NOT_FOUND:
+ headers = "HTTP/1.1 404 Not Found\n";
+ break;
+ case net::ERR_ABORTED:
+ headers = "HTTP/1.1 503 Request Aborted\n";
+ break;
+ case net::ERR_ACCESS_DENIED:
+ headers = "HTTP/1.1 403 Forbidden\n";
+ break;
+ case net::ERR_FAILED:
+ headers = "HTTP/1.1 400 Request Failed\n";
+ break;
+ default:
+ headers = "HTTP/1.1 500 Internal Error\n";
+ break;
+ }
+ 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_client->OnReceiveResponse(m_head);
+ CompleteWithFailure(net::Error(error));
+ }
+ void notifyReadyRead() override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ readAvailableData();
+ }
+ void notifyReadyWrite(MojoResult result, const mojo::HandleSignalsState &state)
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ if (result != MOJO_RESULT_OK) {
+ CompleteWithFailure(net::ERR_FAILED);
+ return;
+ }
+ readAvailableData();
+ }
+ bool readAvailableData()
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ for (;;) {
+ if (m_error || !m_device)
+ break;
+
+ void *buffer = nullptr;
+ uint32_t bufferSize = 0;
+ MojoResult beginResult = m_pipe.producer_handle->BeginWriteData(
+ &buffer, &bufferSize, MOJO_BEGIN_WRITE_DATA_FLAG_NONE);
+ if (beginResult == MOJO_RESULT_SHOULD_WAIT)
+ return false; // Wait for pipe watcher
+ if (beginResult != MOJO_RESULT_OK)
+ break;
+ if (m_maxBytesToRead > 0 && m_maxBytesToRead <= int64_t{std::numeric_limits<uint32_t>::max()})
+ bufferSize = std::min(bufferSize, uint32_t(m_maxBytesToRead));
+
+ int readResult = m_device->read(static_cast<char *>(buffer), bufferSize);
+ uint32_t bytesRead = std::max(readResult, 0);
+ m_pipe.producer_handle->EndWriteData(bytesRead);
+ m_totalBytesRead += bytesRead;
+ m_client->OnTransferSizeUpdated(m_totalBytesRead);
+
+ if (m_device->atEnd() || (m_maxBytesToRead > 0 && m_totalBytesRead >= m_maxBytesToRead)) {
+ OnTransferComplete(MOJO_RESULT_OK);
+ return true; // Done with reading
+ }
+
+ if (readResult == 0)
+ return false; // Wait for readyRead
+ if (readResult < 0)
+ break;
+ }
+
+ CompleteWithFailure(m_error ? net::Error(m_error) : net::ERR_FAILED);
+ return true; // Done with reading
+ }
+ bool ParseRange(const net::HttpRequestHeaders &headers)
+ {
+ std::string range_header;
+ if (headers.GetHeader(net::HttpRequestHeaders::kRange, &range_header)) {
+ std::vector<net::HttpByteRange> ranges;
+ if (net::HttpUtil::ParseRangeHeader(range_header, &ranges)) {
+ // Chromium doesn't support multirange requests.
+ if (ranges.size() == 1) {
+ m_byteRange = ranges[0];
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+ base::TaskRunner *taskRunner() override
+ {
+ DCHECK(m_taskRunner->RunsTasksInCurrentSequence());
+ return m_taskRunner.get();
+ }
+
+ scoped_refptr<base::SequencedTaskRunner> m_taskRunner;
+ scoped_refptr<URLRequestCustomJobProxy> m_proxy;
+
+ mojo::Binding<network::mojom::URLLoader> m_binding;
+ network::mojom::URLLoaderClientPtr m_client;
+ mojo::DataPipe m_pipe;
+ std::unique_ptr<mojo::SimpleWatcher> m_watcher;
+
+ net::HttpByteRange m_byteRange;
+ int64_t m_totalSize = 0;
+ int64_t m_maxBytesToRead = -1;
+ network::ResourceRequest m_request;
+ network::ResourceResponseHead m_head;
+ qint64 m_totalBytesRead = 0;
+ bool m_corsEnabled;
+
+ base::WeakPtrFactory<CustomURLLoader> m_weakPtrFactory{this};
+
+ DISALLOW_COPY_AND_ASSIGN(CustomURLLoader);
+};
+
+class CustomURLLoaderFactory : public network::mojom::URLLoaderFactory {
+public:
+ CustomURLLoaderFactory(ProfileAdapter *profileAdapter)
+ : m_taskRunner(base::CreateSequencedTaskRunner({ content::BrowserThread::IO }))
+ , m_profileAdapter(profileAdapter)
+ {
+ }
+ ~CustomURLLoaderFactory() override = default;
+
+ // network::mojom::URLLoaderFactory:
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader,
+ int32_t routing_id,
+ int32_t request_id,
+ uint32_t options,
+ const network::ResourceRequest &request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag &traffic_annotation) override
+ {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ Q_UNUSED(routing_id);
+ Q_UNUSED(request_id);
+ Q_UNUSED(options);
+ Q_UNUSED(traffic_annotation);
+
+ m_taskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&CustomURLLoader::CreateAndStart, request,
+ std::move(loader), client.PassInterface(),
+ m_profileAdapter));
+
+ }
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) override
+ {
+ m_receivers.Add(this, std::move(receiver));
+ }
+
+ const scoped_refptr<base::SequencedTaskRunner> m_taskRunner;
+ mojo::ReceiverSet<network::mojom::URLLoaderFactory> m_receivers;
+ QPointer<ProfileAdapter> m_profileAdapter;
+ DISALLOW_COPY_AND_ASSIGN(CustomURLLoaderFactory);
+};
+
+} // namespace
+
+std::unique_ptr<network::mojom::URLLoaderFactory> CreateCustomURLLoaderFactory(ProfileAdapter *profileAdapter)
+{
+ return std::make_unique<CustomURLLoaderFactory>(profileAdapter);
+}
+
+} // namespace QtWebEngineCore
+
diff --git a/src/core/net/url_request_context_getter_qt.h b/src/core/net/custom_url_loader_factory.h
index a6ef6eae0..58adf4b79 100644
--- a/src/core/net/url_request_context_getter_qt.h
+++ b/src/core/net/custom_url_loader_factory.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -37,27 +37,33 @@
**
****************************************************************************/
-#ifndef URL_REQUEST_CONTEXT_GETTER_QT_H
-#define URL_REQUEST_CONTEXT_GETTER_QT_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 "net/url_request/url_request_context_getter.h"
+#ifndef CUSTOM_URL_LOADER_FACTORY_H_
+#define CUSTOM_URL_LOADER_FACTORY_H_
-namespace QtWebEngineCore {
+#include <memory>
-class ProfileIODataQt;
+namespace network {
+namespace mojom {
+class URLLoaderFactory;
+} // namespace mojom
+} // namespace network
-class URLRequestContextGetterQt : public net::URLRequestContextGetter
-{
-public:
- URLRequestContextGetterQt(ProfileIODataQt *data);
- net::URLRequestContext *GetURLRequestContext() override;
- scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner() const override;
+namespace QtWebEngineCore {
+class ProfileAdapter;
-private:
- virtual ~URLRequestContextGetterQt();
- ProfileIODataQt *m_profileIOData;
-};
+std::unique_ptr<network::mojom::URLLoaderFactory> CreateCustomURLLoaderFactory(ProfileAdapter *profileAdapter);
} // namespace QtWebEngineCore
-#endif // URL_REQUEST_CONTEXT_GETTER_QT_H
+#endif // CUSTOM_URL_LOADER_FACTORY_H_
diff --git a/src/core/net/network_delegate_qt.cpp b/src/core/net/network_delegate_qt.cpp
deleted file mode 100644
index 7d3801ffe..000000000
--- a/src/core/net/network_delegate_qt.cpp
+++ /dev/null
@@ -1,305 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "network_delegate_qt.h"
-
-#include "base/task/post_task.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_request_info.h"
-#include "net/base/load_flags.h"
-#include "net/url_request/url_request.h"
-#include "ui/base/page_transition_types.h"
-
-#include "profile_adapter.h"
-#include "cookie_monster_delegate_qt.h"
-#include "profile_io_data_qt.h"
-#include "qwebengineurlrequestinfo.h"
-#include "qwebengineurlrequestinfo_p.h"
-#include "qwebengineurlrequestinterceptor.h"
-#include "type_conversion.h"
-#include "web_contents_adapter_client.h"
-#include "web_contents_view_qt.h"
-#include "url_request_notification.h"
-
-namespace QtWebEngineCore {
-
-WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition)
-{
- if (ui::PageTransitionIsRedirect(transition))
- return WebContentsAdapterClient::RedirectNavigation;
-
- int32_t qualifier = ui::PageTransitionGetQualifier(transition);
-
- if (qualifier & ui::PAGE_TRANSITION_FORWARD_BACK)
- return WebContentsAdapterClient::BackForwardNavigation;
-
- ui::PageTransition strippedTransition = ui::PageTransitionStripQualifier(transition);
-
- switch (strippedTransition) {
- case ui::PAGE_TRANSITION_LINK:
- return WebContentsAdapterClient::LinkNavigation;
- case ui::PAGE_TRANSITION_TYPED:
- return WebContentsAdapterClient::TypedNavigation;
- case ui::PAGE_TRANSITION_FORM_SUBMIT:
- return WebContentsAdapterClient::FormSubmittedNavigation;
- case ui::PAGE_TRANSITION_RELOAD:
- return WebContentsAdapterClient::ReloadNavigation;
- default:
- return WebContentsAdapterClient::OtherNavigation;
- }
-}
-
-static QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType)
-{
- if (resourceType >= content::ResourceType::kMainFrame && resourceType <= content::ResourceType::kMaxValue)
- return static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType);
- return QWebEngineUrlRequestInfo::ResourceTypeUnknown;
-}
-
-static QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType)
-{
- return static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType);
-}
-
-NetworkDelegateQt::NetworkDelegateQt(ProfileIODataQt *data)
- : m_profileIOData(data)
-{
-}
-
-int NetworkDelegateQt::OnBeforeURLRequest(net::URLRequest *request, net::CompletionOnceCallback callback, GURL *newUrl)
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_profileIOData);
- content::ResourceRequestInfo *resourceInfo = content::ResourceRequestInfo::ForRequest(request);
-
- content::ResourceType resourceType = content::ResourceType::kMaxValue;
- WebContentsAdapterClient::NavigationType navigationType = WebContentsAdapterClient::OtherNavigation;
-
- if (resourceInfo) {
- resourceType = resourceInfo->GetResourceType();
- navigationType = pageTransitionToNavigationType(resourceInfo->GetPageTransition());
- }
-
- const QUrl qUrl = toQt(request->url());
-
- QUrl firstPartyUrl = QUrl();
- if (resourceType == content::ResourceType::kSubFrame)
- firstPartyUrl = toQt(request->first_party_url());
- else
- firstPartyUrl = toQt(request->site_for_cookies());
-
- const QUrl initiator = request->initiator().has_value() ? toQt(request->initiator()->GetURL()) : QUrl();
-
- QWebEngineUrlRequestInfoPrivate *infoPrivate = new QWebEngineUrlRequestInfoPrivate(toQt(resourceType),
- toQt(navigationType),
- qUrl,
- firstPartyUrl,
- initiator,
- QByteArray::fromStdString(request->method()));
- QWebEngineUrlRequestInfo requestInfo(infoPrivate);
-
- // Deprecated =begin
- // quick peek if deprecated
-
- if (m_profileIOData->isInterceptorDeprecated()) {
- QWebEngineUrlRequestInterceptor *profileInterceptor = m_profileIOData->acquireInterceptor();
- if (profileInterceptor && m_profileIOData->isInterceptorDeprecated()) {
- profileInterceptor->interceptRequest(requestInfo);
- m_profileIOData->releaseInterceptor();
- if (requestInfo.changed()) {
- int result = infoPrivate->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
-
- if (qUrl != infoPrivate->url)
- *newUrl = toGurl(infoPrivate->url);
-
- if (!infoPrivate->extraHeaders.isEmpty()) {
- auto end = infoPrivate->extraHeaders.constEnd();
- for (auto header = infoPrivate->extraHeaders.constBegin(); header != end; ++header) {
- std::string h = header.key().toStdString();
- if (base::LowerCaseEqualsASCII(h, "referer")) {
- request->SetReferrer(header.value().toStdString());
- } else {
- request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true);
- }
- }
- }
-
- if (result != net::OK)
- return result;
-
- requestInfo.resetChanged();
- }
- } else {
- m_profileIOData->releaseInterceptor();
- }
- }
- // Deprecated =cut
-
- if (!resourceInfo)
- return net::OK;
-
- // try to bail out
- if (!m_profileIOData->hasPageInterceptors() && (!m_profileIOData->requestInterceptor() || m_profileIOData->isInterceptorDeprecated()) &&
- !content::IsResourceTypeFrame(resourceType))
- return net::OK;
-
- auto webContentsGetter = resourceInfo->GetWebContentsGetterForRequest();
- new URLRequestNotification(
- request,
- resourceInfo->IsMainFrame(),
- newUrl,
- std::move(requestInfo),
- webContentsGetter,
- std::move(callback),
- m_profileIOData->profileAdapter()
- );
-
- // We'll run the callback after we notified the UI thread.
- return net::ERR_IO_PENDING;
-}
-
-void NetworkDelegateQt::OnURLRequestDestroyed(net::URLRequest *) {}
-
-void NetworkDelegateQt::OnCompleted(net::URLRequest * /*request*/, bool /*started*/, int /*net_error*/) {}
-
-bool NetworkDelegateQt::OnCanSetCookie(const net::URLRequest &request, const net::CanonicalCookie & /*cookie*/,
- net::CookieOptions *, bool allowedFromCaller)
-{
- if (!allowedFromCaller)
- return false;
- return canSetCookies(request.site_for_cookies(), request.url(), std::string());
-}
-
-bool NetworkDelegateQt::OnCanGetCookies(const net::URLRequest &request, const net::CookieList &, bool allowedFromCaller)
-{
- if (!allowedFromCaller)
- return false;
- return canGetCookies(request.site_for_cookies(), request.url());
-}
-
-bool NetworkDelegateQt::OnForcePrivacyMode(const GURL &url, const GURL &site_for_cookies) const
-{
- return false;
- // FIXME: This is what the NetworkContext implementation does (changes tst_QWebEngineCookieStore tests since 72)
- // return !canGetCookies(site_for_cookies, url);
-}
-
-bool NetworkDelegateQt::canSetCookies(const GURL &first_party, const GURL &url, const std::string &cookie_line) const
-{
- Q_ASSERT(m_profileIOData);
- return m_profileIOData->canSetCookie(toQt(first_party), QByteArray::fromStdString(cookie_line), toQt(url));
-}
-
-bool NetworkDelegateQt::canGetCookies(const GURL &first_party, const GURL &url) const
-{
- Q_ASSERT(m_profileIOData);
- return m_profileIOData->canGetCookies(toQt(first_party), toQt(url));
-}
-
-int NetworkDelegateQt::OnBeforeStartTransaction(net::URLRequest *, net::CompletionOnceCallback, net::HttpRequestHeaders *)
-{
- return net::OK;
-}
-
-void NetworkDelegateQt::OnBeforeSendHeaders(net::URLRequest *request, const net::ProxyInfo &proxy_info,
- const net::ProxyRetryInfoMap &proxy_retry_info,
- net::HttpRequestHeaders *headers)
-{}
-
-void NetworkDelegateQt::OnStartTransaction(net::URLRequest *request, const net::HttpRequestHeaders &headers) {}
-
-int NetworkDelegateQt::OnHeadersReceived(net::URLRequest *, net::CompletionOnceCallback, const net::HttpResponseHeaders *,
- scoped_refptr<net::HttpResponseHeaders> *, GURL *)
-{
- return net::OK;
-}
-
-void NetworkDelegateQt::OnBeforeRedirect(net::URLRequest *, const GURL &) {}
-
-void NetworkDelegateQt::OnResponseStarted(net::URLRequest *, int) {}
-
-void NetworkDelegateQt::OnNetworkBytesReceived(net::URLRequest *, int64_t) {}
-
-void NetworkDelegateQt::OnNetworkBytesSent(net::URLRequest *, int64_t) {}
-
-void NetworkDelegateQt::OnPACScriptError(int, const base::string16 &) {}
-
-net::NetworkDelegate::AuthRequiredResponse NetworkDelegateQt::OnAuthRequired(net::URLRequest *,
- const net::AuthChallengeInfo &,
- AuthCallback, net::AuthCredentials *)
-{
- return AUTH_REQUIRED_RESPONSE_NO_ACTION;
-}
-
-bool NetworkDelegateQt::OnCanAccessFile(const net::URLRequest &, const base::FilePath &, const base::FilePath &) const
-{
- return true;
-}
-
-bool NetworkDelegateQt::OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest &, const GURL &,
- const GURL &) const
-{
- return false;
-}
-
-bool NetworkDelegateQt::OnCanQueueReportingReport(const url::Origin &origin) const
-{
- return false;
-}
-
-void NetworkDelegateQt::OnCanSendReportingReports(std::set<url::Origin> origins,
- base::OnceCallback<void(std::set<url::Origin>)> result_callback) const
-{
- std::move(result_callback).Run(std::set<url::Origin>());
-}
-
-bool NetworkDelegateQt::OnCanSetReportingClient(const url::Origin &origin, const GURL &endpoint) const
-{
- return false;
-}
-
-bool NetworkDelegateQt::OnCanUseReportingClient(const url::Origin &origin, const GURL &endpoint) const
-{
- return false;
-}
-
-} // namespace QtWebEngineCore
diff --git a/src/core/net/network_delegate_qt.h b/src/core/net/network_delegate_qt.h
deleted file mode 100644
index f294c6c7c..000000000
--- a/src/core/net/network_delegate_qt.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef NETWORK_DELEGATE_QT_H
-#define NETWORK_DELEGATE_QT_H
-
-#include "net/base/network_delegate.h"
-#include "net/base/net_errors.h"
-
-#include <QUrl>
-#include <QSet>
-
-namespace content {
-class WebContents;
-}
-
-namespace QtWebEngineCore {
-
-class ProfileIODataQt;
-
-class NetworkDelegateQt : public net::NetworkDelegate
-{
- ProfileIODataQt *m_profileIOData;
-
-public:
- NetworkDelegateQt(ProfileIODataQt *data);
-
- // net::NetworkDelegate implementation
- int OnBeforeURLRequest(net::URLRequest *request, net::CompletionOnceCallback callback, GURL *new_url) override;
- void OnURLRequestDestroyed(net::URLRequest *request) override;
- bool OnCanSetCookie(const net::URLRequest &request, const net::CanonicalCookie &cookie, net::CookieOptions *options,
- bool) override;
- int OnBeforeStartTransaction(net::URLRequest *request, const net::CompletionOnceCallback callback,
- net::HttpRequestHeaders *headers) override;
- void OnBeforeSendHeaders(net::URLRequest *request, const net::ProxyInfo &proxy_info,
- const net::ProxyRetryInfoMap &proxy_retry_info, net::HttpRequestHeaders *headers) override;
- void OnStartTransaction(net::URLRequest *request, const net::HttpRequestHeaders &headers) override;
- int OnHeadersReceived(net::URLRequest *, net::CompletionOnceCallback, const net::HttpResponseHeaders *,
- scoped_refptr<net::HttpResponseHeaders> *, GURL *) override;
- void OnBeforeRedirect(net::URLRequest *, const GURL &) override;
- void OnResponseStarted(net::URLRequest *, int) override;
- void OnNetworkBytesReceived(net::URLRequest *, int64_t) override;
- void OnNetworkBytesSent(net::URLRequest *, int64_t) override;
- void OnCompleted(net::URLRequest *request, bool started, int net_error) override;
- void OnPACScriptError(int, const base::string16 &) override;
- net::NetworkDelegate::AuthRequiredResponse OnAuthRequired(net::URLRequest *, const net::AuthChallengeInfo &,
- AuthCallback, net::AuthCredentials *) override;
- bool OnCanGetCookies(const net::URLRequest &, const net::CookieList &, bool) override;
- bool OnCanAccessFile(const net::URLRequest &, const base::FilePath &, const base::FilePath &) const override;
- bool OnForcePrivacyMode(const GURL &, const GURL &) const override;
- bool OnCancelURLRequestWithPolicyViolatingReferrerHeader(const net::URLRequest &, const GURL &,
- const GURL &) const override;
-
- bool OnCanQueueReportingReport(const url::Origin &origin) const override;
- void OnCanSendReportingReports(std::set<url::Origin> origins,
- base::OnceCallback<void(std::set<url::Origin>)> result_callback) const override;
- bool OnCanSetReportingClient(const url::Origin &origin, const GURL &endpoint) const override;
- bool OnCanUseReportingClient(const url::Origin &origin, const GURL &endpoint) const override;
-
- bool canSetCookies(const GURL &first_party, const GURL &url, const std::string &cookie_line) const;
- bool canGetCookies(const GURL &first_party, const GURL &url) const;
-};
-
-} // namespace QtWebEngineCore
-
-#endif // NETWORK_DELEGATE_QT_H
diff --git a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
new file mode 100644
index 000000000..2b6158f4a
--- /dev/null
+++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp
@@ -0,0 +1,135 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "plugin_response_interceptor_url_loader_throttle.h"
+
+#include "base/bind.h"
+#include "base/task/post_task.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/download_request_utils.h"
+#include "content/public/browser/download_utils.h"
+#include "content/public/common/resource_type.h"
+#include "extensions/common/constants.h"
+#include "extensions/common/extension.h"
+
+#include "extensions/extension_system_qt.h"
+#include "profile_adapter.h"
+#include "profile_io_data_qt.h"
+#include "profile_qt.h"
+#include "web_contents_delegate_qt.h"
+
+#include <string>
+
+namespace QtWebEngineCore {
+
+void onPdfStreamIntercepted(const GURL &original_url, std::string extension_id, int frame_tree_node_id)
+{
+ content::WebContents *web_contents = content::WebContents::FromFrameTreeNodeId(frame_tree_node_id);
+ if (!web_contents)
+ return;
+
+ WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt *>(web_contents->GetDelegate());
+ if (!contentsDelegate)
+ return;
+
+ WebEngineSettings *settings = contentsDelegate->webEngineSettings();
+ if (!settings->testAttribute(WebEngineSettings::PdfViewerEnabled)
+ || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) {
+ // If the applications has been set up to always download PDF files to open them in an
+ // external viewer, trigger the download.
+ std::unique_ptr<download::DownloadUrlParameters> params(
+ content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(web_contents, original_url,
+ MISSING_TRAFFIC_ANNOTATION));
+ content::BrowserContext::GetDownloadManager(web_contents->GetBrowserContext())->DownloadUrl(std::move(params));
+ return;
+ }
+
+ // The URL passes the original pdf resource url, that will be requested
+ // by the pdf viewer extension page.
+ content::NavigationController::LoadURLParams params(
+ GURL(base::StringPrintf("%s://%s/index.html?%s", extensions::kExtensionScheme,
+ extension_id.c_str(), original_url.spec().c_str())));
+
+ params.frame_tree_node_id = frame_tree_node_id;
+ web_contents->GetController().LoadURLWithParams(params);
+}
+
+
+PluginResponseInterceptorURLLoaderThrottle::PluginResponseInterceptorURLLoaderThrottle(
+ content::ResourceContext *resource_context, int resource_type, int frame_tree_node_id)
+ : m_resource_context(resource_context), m_resource_type(resource_type), m_frame_tree_node_id(frame_tree_node_id)
+{}
+
+PluginResponseInterceptorURLLoaderThrottle::PluginResponseInterceptorURLLoaderThrottle(
+ content::BrowserContext *browser_context, int resource_type, int frame_tree_node_id)
+ : m_browser_context(browser_context), m_resource_type(resource_type), m_frame_tree_node_id(frame_tree_node_id)
+{}
+
+void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL &response_url,
+ network::ResourceResponseHead *response_head,
+ bool *defer)
+{
+ Q_UNUSED(defer);
+ if (content::download_utils::MustDownload(response_url, response_head->headers.get(), response_head->mime_type))
+ return;
+
+ if (m_resource_context) {
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ } else {
+ DCHECK(m_browser_context);
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ }
+
+ std::string extension_id;
+ // FIXME: We should use extensions::InfoMap in the future:
+ if (response_head->mime_type == "application/pdf")
+ extension_id = extension_misc::kPdfExtensionId;
+ if (extension_id.empty())
+ return;
+
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(&onPdfStreamIntercepted,
+ response_url,
+ extension_id,
+ m_frame_tree_node_id));
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/net/url_request_notification.h b/src/core/net/plugin_response_interceptor_url_loader_throttle.h
index 673e07bf0..1fc9e654f 100644
--- a/src/core/net/url_request_notification.h
+++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.h
@@ -37,50 +37,40 @@
**
****************************************************************************/
-#ifndef URL_REQUEST_NOTIFIACTION_H
-#define URL_REQUEST_NOTIFIACTION_H
+#ifndef PLUGIN_RESPONSE_INTERCEPTOR_URL_LOADER_THROTTLE_H_
+#define PLUGIN_RESPONSE_INTERCEPTOR_URL_LOADER_THROTTLE_H_
-#include "content/public/browser/resource_request_info.h"
-#include "net/base/completion_once_callback.h"
-#include "qwebengineurlrequestinfo.h"
-#include <QPointer>
+#include "base/macros.h"
+#include "third_party/blink/public/common/loader/url_loader_throttle.h"
-class GURL;
-
-namespace net {
-class URLRequest;
+namespace content {
+class BrowserContext;
+class ResourceContext;
}
namespace QtWebEngineCore {
-class ProfileAdapter;
-class ProfileIoDataQt;
-
-// Notifies WebContentsAdapterClient of a new URLRequest.
-class URLRequestNotification
+class PluginResponseInterceptorURLLoaderThrottle : public blink::URLLoaderThrottle
{
public:
- URLRequestNotification(net::URLRequest *request,
- bool isMainFrameRequest,
- GURL *newUrl,
- QWebEngineUrlRequestInfo &&requestInfo,
- content::ResourceRequestInfo::WebContentsGetter webContentsGetter,
- net::CompletionOnceCallback callback,
- QPointer<ProfileAdapter> adapter);
- ~URLRequestNotification() = default;
- void cancel();
- void notify();
- void complete(int error);
+ PluginResponseInterceptorURLLoaderThrottle(content::ResourceContext *resource_context,
+ int resource_type, int frame_tree_node_id);
+ PluginResponseInterceptorURLLoaderThrottle(content::BrowserContext *browser_context,
+ int resource_type, int frame_tree_node_id);
+ ~PluginResponseInterceptorURLLoaderThrottle() override = default;
private:
- net::URLRequest *m_request; //used only by io thread
- bool m_isMainFrameRequest;
- GURL *m_newUrl;
- const QUrl m_originalUrl;
- QWebEngineUrlRequestInfo m_requestInfo;
- content::ResourceRequestInfo::WebContentsGetter m_webContentsGetter;
- net::CompletionOnceCallback m_callback;
- QPointer<ProfileAdapter> m_profileAdapter;
+ // content::URLLoaderThrottle overrides;
+ void WillProcessResponse(const GURL &response_url, network::ResourceResponseHead *response_head, bool *defer) override;
+
+ content::ResourceContext *m_resource_context = nullptr;
+ content::BrowserContext *m_browser_context = nullptr;
+ const int m_resource_type;
+ const int m_frame_tree_node_id;
+
+ DISALLOW_COPY_AND_ASSIGN(PluginResponseInterceptorURLLoaderThrottle);
};
-}
-#endif
+
+} // namespace QtWebEngineCore
+
+#endif // PLUGIN_RESPONSE_INTERCEPTOR_URL_LOADER_THROTTLE_H_
diff --git a/src/core/net/proxy_config_monitor.cpp b/src/core/net/proxy_config_monitor.cpp
new file mode 100644
index 000000000..a0aaf0c05
--- /dev/null
+++ b/src/core/net/proxy_config_monitor.cpp
@@ -0,0 +1,124 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// originally based on chrome/browser/net/proxy_config_monitor.cc
+// Copyright 2017 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 file.
+
+#include "profile_qt.h"
+#include "proxy_config_monitor.h"
+#include "proxy_config_service_qt.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/task/post_task.h"
+#include "build/build_config.h"
+#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "net/proxy_resolution/proxy_resolution_service.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+
+#include <utility>
+
+using content::BrowserThread;
+
+ProxyConfigMonitor::ProxyConfigMonitor(PrefService *prefs)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ proxy_config_service_.reset(
+ new ProxyConfigServiceQt(
+ prefs, base::CreateSingleThreadTaskRunner({ BrowserThread::UI })));
+
+ proxy_config_service_->AddObserver(this);
+}
+
+ProxyConfigMonitor::~ProxyConfigMonitor()
+{
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)
+ || !BrowserThread::IsThreadInitialized(BrowserThread::UI));
+ proxy_config_service_->RemoveObserver(this);
+}
+
+void ProxyConfigMonitor::AddToNetworkContextParams(
+ network::mojom::NetworkContextParams *network_context_params)
+{
+ mojo::PendingRemote<network::mojom::ProxyConfigClient> proxy_config_client;
+ network_context_params->proxy_config_client_receiver =
+ proxy_config_client.InitWithNewPipeAndPassReceiver();
+ proxy_config_client_set_.Add(std::move(proxy_config_client));
+
+ poller_receiver_set_.Add(this,
+ network_context_params->proxy_config_poller_client.InitWithNewPipeAndPassReceiver());
+
+ net::ProxyConfigWithAnnotation proxy_config;
+ net::ProxyConfigService::ConfigAvailability availability =
+ proxy_config_service_->GetLatestProxyConfig(&proxy_config);
+ if (availability != net::ProxyConfigService::CONFIG_PENDING)
+ network_context_params->initial_proxy_config = proxy_config;
+}
+
+void ProxyConfigMonitor::OnProxyConfigChanged(
+ const net::ProxyConfigWithAnnotation &config,
+ net::ProxyConfigService::ConfigAvailability availability)
+{
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)
+ || !BrowserThread::IsThreadInitialized(BrowserThread::UI));
+ for (const auto &proxy_config_client : proxy_config_client_set_) {
+ switch (availability) {
+ case net::ProxyConfigService::CONFIG_VALID:
+ proxy_config_client->OnProxyConfigUpdated(config);
+ break;
+ case net::ProxyConfigService::CONFIG_UNSET:
+ proxy_config_client->OnProxyConfigUpdated(net::ProxyConfigWithAnnotation::CreateDirect());
+ break;
+ case net::ProxyConfigService::CONFIG_PENDING:
+ NOTREACHED();
+ break;
+ }
+ }
+}
+
+void ProxyConfigMonitor::OnLazyProxyConfigPoll()
+{
+ proxy_config_service_->OnLazyPoll();
+}
diff --git a/src/core/net/proxy_config_monitor.h b/src/core/net/proxy_config_monitor.h
new file mode 100644
index 000000000..fda6a6fb9
--- /dev/null
+++ b/src/core/net/proxy_config_monitor.h
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// originally based on chrome/browser/net/proxy_config_monitor.h
+// Copyright 2017 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 file.
+
+#ifndef PROXY_CONFIG_MONITOR_H
+#define PROXY_CONFIG_MONITOR_H
+
+#include <memory>
+#include <string>
+
+#include "base/macros.h"
+#include "build/buildflag.h"
+#include "extensions/buildflags/buildflags.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "mojo/public/cpp/bindings/remote_set.h"
+#include "net/proxy_resolution/proxy_config_service.h"
+#include "services/network/public/mojom/network_context.mojom-forward.h"
+#include "services/network/public/mojom/network_service.mojom-forward.h"
+#include "services/network/public/mojom/proxy_config.mojom-forward.h"
+#include "services/network/public/mojom/proxy_config_with_annotation.mojom.h"
+
+namespace net {
+class ProxyConfigWithAnnotation;
+}
+
+class PrefService;
+class ProxyConfigServiceQt;
+
+// Tracks the ProxyConfig to use, and passes any updates to a NetworkContext's
+// ProxyConfigClient. This also responds to errors related to proxy settings
+// from the NetworkContext, and forwards them any listening Chrome extensions
+// associated with the profile.
+class ProxyConfigMonitor : public net::ProxyConfigService::Observer,
+ public network::mojom::ProxyConfigPollerClient
+{
+public:
+ explicit ProxyConfigMonitor(PrefService *prefs = nullptr);
+
+ ~ProxyConfigMonitor() override;
+
+ // Populates proxy-related fields of |network_context_params|. Updated
+ // ProxyConfigs will be sent to a NetworkContext created with those params
+ // whenever the configuration changes. Can be called more than once to inform
+ // multiple NetworkContexts of proxy changes.
+ void AddToNetworkContextParams(network::mojom::NetworkContextParams *network_context_params);
+
+private:
+ // net::ProxyConfigService::Observer implementation:
+ void OnProxyConfigChanged(const net::ProxyConfigWithAnnotation &config,
+ net::ProxyConfigService::ConfigAvailability availability) override;
+
+ // network::mojom::ProxyConfigPollerClient implementation:
+ void OnLazyProxyConfigPoll() override;
+
+ std::unique_ptr<ProxyConfigServiceQt> proxy_config_service_;
+
+ mojo::ReceiverSet<network::mojom::ProxyConfigPollerClient> poller_receiver_set_;
+ mojo::RemoteSet<network::mojom::ProxyConfigClient> proxy_config_client_set_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyConfigMonitor);
+};
+
+#endif // !PROXY_CONFIG_MONITOR_H
diff --git a/src/core/net/proxy_config_service_qt.cpp b/src/core/net/proxy_config_service_qt.cpp
index 8016c7e83..59884961d 100644
--- a/src/core/net/proxy_config_service_qt.cpp
+++ b/src/core/net/proxy_config_service_qt.cpp
@@ -46,8 +46,9 @@
#include "proxy_config_service_qt.h"
#include "base/bind.h"
-#include "content/public/browser/browser_thread.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
+#include "content/public/browser/browser_thread.h"
+#include "net/proxy_resolution/proxy_resolution_service.h"
using content::BrowserThread;
@@ -69,34 +70,40 @@ net::ProxyServer ProxyConfigServiceQt::fromQNetworkProxy(const QNetworkProxy &qt
}
}
-ProxyConfigServiceQt::ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService,
- const net::ProxyConfigWithAnnotation &initialConfig,
- ProxyPrefs::ConfigState initialState)
- : m_baseService(baseService.release())
+ProxyConfigServiceQt::ProxyConfigServiceQt(PrefService *prefService,
+ const scoped_refptr<base::SingleThreadTaskRunner> &taskRunner)
+ : m_baseService(net::ProxyResolutionService::CreateSystemProxyConfigService(taskRunner))
, m_usesSystemConfiguration(false)
, m_registeredObserver(false)
- , m_prefConfig(initialConfig)
- , m_perfState(initialState)
-{}
+ , m_prefState(prefService
+ ? PrefProxyConfigTrackerImpl::ReadPrefConfig(prefService, &m_prefConfig)
+ : ProxyPrefs::CONFIG_UNSET)
+{
+ DETACH_FROM_SEQUENCE(m_sequenceChecker);
+}
ProxyConfigServiceQt::~ProxyConfigServiceQt()
{
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
if (m_registeredObserver && m_baseService.get())
m_baseService->RemoveObserver(this);
}
void ProxyConfigServiceQt::AddObserver(net::ProxyConfigService::Observer *observer)
{
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
m_observers.AddObserver(observer);
}
void ProxyConfigServiceQt::RemoveObserver(net::ProxyConfigService::Observer *observer)
{
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
m_observers.RemoveObserver(observer);
}
net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxyConfig(net::ProxyConfigWithAnnotation *config)
{
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
m_usesSystemConfiguration = QNetworkProxyFactory::usesSystemConfiguration();
if (m_usesSystemConfiguration) {
// Use Chromium's base service to retrieve system settings
@@ -106,7 +113,7 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxy
systemAvailability = m_baseService->GetLatestProxyConfig(&systemConfig);
ProxyPrefs::ConfigState configState;
systemAvailability = PrefProxyConfigTrackerImpl::GetEffectiveProxyConfig(
- m_perfState, m_prefConfig, systemAvailability, systemConfig,
+ m_prefState, m_prefConfig, systemAvailability, systemConfig,
false, &configState, config);
RegisterObserver();
return systemAvailability;
@@ -151,7 +158,7 @@ net::ProxyConfigService::ConfigAvailability ProxyConfigServiceQt::GetLatestProxy
void ProxyConfigServiceQt::OnLazyPoll()
{
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
// We need to update if
// - setUseSystemConfiguration() was called in between
@@ -168,7 +175,7 @@ void ProxyConfigServiceQt::OnLazyPoll()
// Called when the base service changed
void ProxyConfigServiceQt::OnProxyConfigChanged(const net::ProxyConfigWithAnnotation &config, ConfigAvailability availability)
{
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
Q_UNUSED(config);
if (!m_usesSystemConfiguration)
@@ -180,6 +187,7 @@ void ProxyConfigServiceQt::OnProxyConfigChanged(const net::ProxyConfigWithAnnota
// Update our observers
void ProxyConfigServiceQt::Update()
{
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
net::ProxyConfigWithAnnotation actual_config;
ConfigAvailability availability = GetLatestProxyConfig(&actual_config);
if (availability == CONFIG_PENDING)
@@ -193,7 +201,7 @@ void ProxyConfigServiceQt::Update()
// in the constructor.
void ProxyConfigServiceQt::RegisterObserver()
{
- DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ DCHECK_CALLED_ON_VALID_SEQUENCE(m_sequenceChecker);
if (!m_registeredObserver && m_baseService.get()) {
m_baseService->AddObserver(this);
m_registeredObserver = true;
diff --git a/src/core/net/proxy_config_service_qt.h b/src/core/net/proxy_config_service_qt.h
index 4d8619055..c0928bc03 100644
--- a/src/core/net/proxy_config_service_qt.h
+++ b/src/core/net/proxy_config_service_qt.h
@@ -42,6 +42,7 @@
#include "base/memory/ref_counted.h"
#include "base/observer_list.h"
+#include "base/single_thread_task_runner.h"
#include "net/proxy_resolution/proxy_config.h"
#include "net/proxy_resolution/proxy_config_service.h"
@@ -50,6 +51,8 @@
#include <QNetworkProxy>
+class PrefService;
+
class ProxyConfigServiceQt
: public net::ProxyConfigService
, public net::ProxyConfigService::Observer
@@ -57,9 +60,8 @@ class ProxyConfigServiceQt
public:
static net::ProxyServer fromQNetworkProxy(const QNetworkProxy &);
- explicit ProxyConfigServiceQt(std::unique_ptr<ProxyConfigService> baseService,
- const net::ProxyConfigWithAnnotation &initialConfig,
- ProxyPrefs::ConfigState initialState);
+ explicit ProxyConfigServiceQt(PrefService *prefService,
+ const scoped_refptr<base::SingleThreadTaskRunner> &taskRunner);
~ProxyConfigServiceQt() override;
// ProxyConfigService implementation:
@@ -92,7 +94,9 @@ private:
// Configuration as defined by prefs.
net::ProxyConfigWithAnnotation m_prefConfig;
- ProxyPrefs::ConfigState m_perfState;
+ ProxyPrefs::ConfigState m_prefState;
+
+ SEQUENCE_CHECKER(m_sequenceChecker);
DISALLOW_COPY_AND_ASSIGN(ProxyConfigServiceQt);
};
diff --git a/src/core/net/proxying_restricted_cookie_manager_qt.cpp b/src/core/net/proxying_restricted_cookie_manager_qt.cpp
new file mode 100644
index 000000000..7ee6c2a15
--- /dev/null
+++ b/src/core/net/proxying_restricted_cookie_manager_qt.cpp
@@ -0,0 +1,241 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// originally based on android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc:
+// Copyright 2019 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 file.
+
+#include "proxying_restricted_cookie_manager_qt.h"
+
+#include "api/qwebenginecookiestore.h"
+#include "api/qwebenginecookiestore_p.h"
+#include "profile_adapter.h"
+#include "profile_qt.h"
+#include "type_conversion.h"
+
+#include "base/memory/ptr_util.h"
+#include "base/task/post_task.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+namespace QtWebEngineCore {
+
+class ProxyingRestrictedCookieManagerListenerQt : public network::mojom::CookieChangeListener {
+public:
+ ProxyingRestrictedCookieManagerListenerQt(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ base::WeakPtr<ProxyingRestrictedCookieManagerQt> restricted_cookie_manager,
+ mojo::PendingRemote<network::mojom::CookieChangeListener> client_listener)
+ : url_(url)
+ , site_for_cookies_(site_for_cookies)
+ , top_frame_origin_(top_frame_origin)
+ , restricted_cookie_manager_(restricted_cookie_manager)
+ , client_listener_(std::move(client_listener))
+ {}
+
+ void OnCookieChange(const net::CookieChangeInfo &change) override
+ {
+ if (restricted_cookie_manager_ && restricted_cookie_manager_->allowCookies(url_, site_for_cookies_))
+ client_listener_->OnCookieChange(change);
+ }
+
+private:
+ const GURL url_;
+ const GURL site_for_cookies_;
+ const url::Origin top_frame_origin_;
+ base::WeakPtr<ProxyingRestrictedCookieManagerQt> restricted_cookie_manager_;
+ mojo::Remote<network::mojom::CookieChangeListener> client_listener_;
+};
+
+// static
+void ProxyingRestrictedCookieManagerQt::CreateAndBind(ProfileIODataQt *profileIoData,
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
+ bool is_service_worker,
+ int process_id,
+ int frame_id,
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&ProxyingRestrictedCookieManagerQt::CreateAndBindOnIoThread,
+ profileIoData,
+ std::move(underlying_rcm),
+ is_service_worker, process_id, frame_id,
+ std::move(receiver)));
+}
+
+
+// static
+void ProxyingRestrictedCookieManagerQt::CreateAndBindOnIoThread(ProfileIODataQt *profileIoData,
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
+ bool is_service_worker,
+ int process_id,
+ int frame_id,
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ auto wrapper = base::WrapUnique(new ProxyingRestrictedCookieManagerQt(
+ profileIoData->getWeakPtrOnIOThread(),
+ std::move(underlying_rcm),
+ is_service_worker, process_id, frame_id));
+ mojo::MakeSelfOwnedReceiver(std::move(wrapper), std::move(receiver));
+}
+
+ProxyingRestrictedCookieManagerQt::ProxyingRestrictedCookieManagerQt(
+ base::WeakPtr<ProfileIODataQt> profileIoData,
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlyingRestrictedCookieManager,
+ bool is_service_worker,
+ int32_t process_id,
+ int32_t frame_id)
+ : m_profileIoData(std::move(profileIoData))
+ , underlying_restricted_cookie_manager_(std::move(underlyingRestrictedCookieManager))
+ , is_service_worker_(is_service_worker)
+ , process_id_(process_id)
+ , frame_id_(frame_id)
+ , weak_factory_(this)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+ProxyingRestrictedCookieManagerQt::~ProxyingRestrictedCookieManagerQt()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+}
+
+void ProxyingRestrictedCookieManagerQt::GetAllForUrl(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ network::mojom::CookieManagerGetOptionsPtr options,
+ 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), std::move(callback));
+ } else {
+ std::move(callback).Run(std::vector<net::CanonicalCookie>());
+ }
+}
+
+void ProxyingRestrictedCookieManagerQt::SetCanonicalCookie(const net::CanonicalCookie &cookie,
+ const GURL &url,
+ const GURL &site_for_cookies, const url::Origin &top_frame_origin,
+ 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, std::move(callback));
+ } else {
+ std::move(callback).Run(false);
+ }
+}
+
+void ProxyingRestrictedCookieManagerQt::AddChangeListener(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ mojo::PendingRemote<network::mojom::CookieChangeListener> listener,
+ AddChangeListenerCallback callback)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ mojo::PendingRemote<network::mojom::CookieChangeListener> proxy_listener_remote;
+ auto proxy_listener =
+ std::make_unique<ProxyingRestrictedCookieManagerListenerQt>(
+ url, site_for_cookies, top_frame_origin,
+ weak_factory_.GetWeakPtr(),
+ std::move(listener));
+
+ mojo::MakeSelfOwnedReceiver(std::move(proxy_listener),
+ proxy_listener_remote.InitWithNewPipeAndPassReceiver());
+
+ underlying_restricted_cookie_manager_->AddChangeListener(url, site_for_cookies, top_frame_origin, std::move(proxy_listener_remote), std::move(callback));
+}
+
+void ProxyingRestrictedCookieManagerQt::SetCookieFromString(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ const std::string &cookie,
+ 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, std::move(callback));
+ } else {
+ std::move(callback).Run();
+ }
+}
+
+void ProxyingRestrictedCookieManagerQt::GetCookiesString(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ 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, std::move(callback));
+ } else {
+ std::move(callback).Run("");
+ }
+}
+
+void ProxyingRestrictedCookieManagerQt::CookiesEnabledFor(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin & /*top_frame_origin*/,
+ CookiesEnabledForCallback callback)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ std::move(callback).Run(allowCookies(url, site_for_cookies));
+}
+
+bool ProxyingRestrictedCookieManagerQt::allowCookies(const GURL &url, const GURL &site_for_cookies) const
+{
+ if (!m_profileIoData)
+ return false;
+ return m_profileIoData->canGetCookies(toQt(site_for_cookies), toQt(url));
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/net/restricted_cookie_manager_qt.h b/src/core/net/proxying_restricted_cookie_manager_qt.h
index 9154f671d..b682075ed 100644
--- a/src/core/net/restricted_cookie_manager_qt.h
+++ b/src/core/net/proxying_restricted_cookie_manager_qt.h
@@ -37,64 +37,91 @@
**
****************************************************************************/
-#ifndef RESTRICTED_COOKIE_MANAGER_QT_H
-#define RESTRICTED_COOKIE_MANAGER_QT_H
+#ifndef PROXYING_RESTRICTED_COOKIE_MANAGER_QT_H
+#define PROXYING_RESTRICTED_COOKIE_MANAGER_QT_H
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
-#include "services/network/restricted_cookie_manager.h"
+#include "mojo/public/cpp/bindings/remote.h"
+#include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
#include "url/gurl.h"
namespace QtWebEngineCore {
class ProfileIODataQt;
-class RestrictedCookieManagerQt : public network::RestrictedCookieManager
+class ProxyingRestrictedCookieManagerQt : public network::mojom::RestrictedCookieManager
{
public:
- RestrictedCookieManagerQt(base::WeakPtr<ProfileIODataQt> profileIoData,
- network::mojom::RestrictedCookieManagerRole role,
- net::CookieStore *cookie_store,
- network::CookieSettings *cookie_settings,
- const url::Origin &origin,
+ // Expects to be called on the UI thread.
+ static void CreateAndBind(ProfileIODataQt *profileIoData,
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
bool is_service_worker,
- int32_t process_id,
- int32_t frame_id);
- ~RestrictedCookieManagerQt() override;
+ int process_id,
+ int frame_id,
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver);
+
+ ~ProxyingRestrictedCookieManagerQt() override;
// network::mojom::RestrictedCookieManager interface:
void GetAllForUrl(const GURL &url,
const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
network::mojom::CookieManagerGetOptionsPtr options,
GetAllForUrlCallback callback) override;
void SetCanonicalCookie(const net::CanonicalCookie& cookie,
const GURL &url,
const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
SetCanonicalCookieCallback callback) override;
void AddChangeListener(const GURL &url,
const GURL &site_for_cookies,
- network::mojom::CookieChangeListenerPtr listener,
+ const url::Origin &top_frame_origin,
+ mojo::PendingRemote<network::mojom::CookieChangeListener> listener,
AddChangeListenerCallback callback) override;
-
+ void SetCookieFromString(const GURL &url,
+ const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
+ const std::string &cookie,
+ SetCookieFromStringCallback callback) override;
void GetCookiesString(const GURL &url,
const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
GetCookiesStringCallback callback) override;
-
void CookiesEnabledFor(const GURL &url,
const GURL &site_for_cookies,
+ const url::Origin &top_frame_origin,
CookiesEnabledForCallback callback) override;
// Internal:
bool allowCookies(const GURL &url, const GURL &site_for_cookies) const;
private:
+ ProxyingRestrictedCookieManagerQt(base::WeakPtr<ProfileIODataQt> profileIoData,
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
+ bool is_service_worker,
+ int32_t process_id,
+ int32_t frame_id);
+
+ static void CreateAndBindOnIoThread(ProfileIODataQt *profileIoData,
+ mojo::PendingRemote<network::mojom::RestrictedCookieManager> underlying_rcm,
+ bool is_service_worker,
+ int process_id,
+ int frame_id,
+ mojo::PendingReceiver<network::mojom::RestrictedCookieManager> receiver);
+
base::WeakPtr<ProfileIODataQt> m_profileIoData;
- base::WeakPtrFactory<RestrictedCookieManagerQt> weak_factory_;
+ mojo::Remote<network::mojom::RestrictedCookieManager> underlying_restricted_cookie_manager_;
+ bool is_service_worker_;
+ int process_id_;
+ int frame_id_;
+
+ base::WeakPtrFactory<ProxyingRestrictedCookieManagerQt> weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(RestrictedCookieManagerQt);
+ DISALLOW_COPY_AND_ASSIGN(ProxyingRestrictedCookieManagerQt);
};
} // namespace QtWebEngineCore
-#endif // RESTRICTED_COOKIE_MANAGER_QT_H
+#endif // PROXYING_RESTRICTED_COOKIE_MANAGER_QT_H
diff --git a/src/core/net/proxying_url_loader_factory_qt.cpp b/src/core/net/proxying_url_loader_factory_qt.cpp
new file mode 100644
index 000000000..a2cb268b0
--- /dev/null
+++ b/src/core/net/proxying_url_loader_factory_qt.cpp
@@ -0,0 +1,558 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "proxying_url_loader_factory_qt.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "base/task/post_task.h"
+#include "components/safe_browsing/common/safebrowsing_constants.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/global_request_id.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_constants.h"
+#include "content/public/common/url_utils.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
+#include "net/http/http_util.h"
+
+#include "api/qwebengineurlrequestinfo_p.h"
+#include "profile_io_data_qt.h"
+#include "type_conversion.h"
+#include "web_contents_adapter_client.h"
+#include "web_contents_view_qt.h"
+
+#include <QVariant>
+
+// originally based on aw_proxying_url_loader_factory.cc:
+// Copyright 2018 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 file.
+
+namespace QtWebEngineCore {
+
+extern WebContentsAdapterClient::NavigationType pageTransitionToNavigationType(ui::PageTransition transition);
+
+static QWebEngineUrlRequestInfo::ResourceType toQt(content::ResourceType resourceType)
+{
+ if (resourceType >= content::ResourceType::kMainFrame && resourceType <= content::ResourceType::kMaxValue)
+ return static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType);
+ return QWebEngineUrlRequestInfo::ResourceTypeUnknown;
+}
+
+static QWebEngineUrlRequestInfo::NavigationType toQt(WebContentsAdapterClient::NavigationType navigationType)
+{
+ return static_cast<QWebEngineUrlRequestInfo::NavigationType>(navigationType);
+}
+
+// Handles intercepted, in-progress requests/responses, so that they can be
+// controlled and modified accordingly.
+class InterceptedRequest : public network::mojom::URLLoader
+ , public network::mojom::URLLoaderClient
+{
+public:
+ InterceptedRequest(int process_id, uint64_t request_id, int32_t routing_id, uint32_t options,
+ const network::ResourceRequest &request, const GURL &top_document_url,
+ const net::MutableNetworkTrafficAnnotationTag &traffic_annotation,
+ ProfileIODataQt *profileData,
+ network::mojom::URLLoaderRequest loader_request, network::mojom::URLLoaderClientPtr client,
+ network::mojom::URLLoaderFactoryPtr target_factory);
+ ~InterceptedRequest() override;
+
+ void Restart();
+ void InterceptOnUIThread();
+
+ // network::mojom::URLLoaderClient
+ void OnReceiveResponse(network::mojom::URLResponseHeadPtr head) override;
+ void OnReceiveRedirect(const net::RedirectInfo &redirect_info, network::mojom::URLResponseHeadPtr head) override;
+ void OnUploadProgress(int64_t current_position, int64_t total_size, OnUploadProgressCallback callback) override;
+ void OnReceiveCachedMetadata(mojo_base::BigBuffer data) override;
+ void OnTransferSizeUpdated(int32_t transfer_size_diff) override;
+ void OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body) override;
+ void OnComplete(const network::URLLoaderCompletionStatus &status) override;
+
+ // network::mojom::URLLoader
+ void FollowRedirect(const std::vector<std::string> &removed_headers,
+ const net::HttpRequestHeaders &modified_headers, const base::Optional<GURL> &new_url) override;
+ void SetPriority(net::RequestPriority priority, int32_t intra_priority_value) override;
+ void PauseReadingBodyFromNet() override;
+ void ResumeReadingBodyFromNet() override;
+
+ void ContinueAfterIntercept();
+
+private:
+ // This is called when the original URLLoaderClient has a connection error.
+ void OnURLLoaderClientError();
+
+ // This is called when the original URLLoader has a connection error.
+ void OnURLLoaderError(uint32_t custom_reason, const std::string &description);
+
+ // Call OnComplete on |target_client_|. If |wait_for_loader_error| is true
+ // then this object will wait for |proxied_loader_binding_| to have a
+ // connection error before destructing.
+ void CallOnComplete(const network::URLLoaderCompletionStatus &status, bool wait_for_loader_error);
+
+ void SendErrorAndCompleteImmediately(int error_code);
+
+ const int process_id_;
+ const uint64_t request_id_;
+ const int32_t routing_id_;
+ const uint32_t options_;
+ bool input_stream_previously_failed_ = false;
+ bool request_was_redirected_ = false;
+
+ // If the |target_loader_| called OnComplete with an error this stores it.
+ // That way the destructor can send it to OnReceivedError if safe browsing
+ // error didn't occur.
+ int error_status_ = net::OK;
+ QUrl m_originalUrl;
+ GURL m_topDocumentUrl;
+
+ network::ResourceRequest request_;
+ network::ResourceResponseHead current_response_;
+
+ const net::MutableNetworkTrafficAnnotationTag traffic_annotation_;
+
+ QWebEngineUrlRequestInfo m_requestInfo;
+ ProfileIODataQt *m_profileData;
+ mojo::Binding<network::mojom::URLLoader> proxied_loader_binding_;
+ network::mojom::URLLoaderClientPtr target_client_;
+
+ mojo::Binding<network::mojom::URLLoaderClient> proxied_client_binding_;
+ network::mojom::URLLoaderPtr target_loader_;
+ network::mojom::URLLoaderFactoryPtr target_factory_;
+
+ base::WeakPtrFactory<InterceptedRequest> m_weakFactory;
+ base::WeakPtr<InterceptedRequest> m_weakPtr;
+ DISALLOW_COPY_AND_ASSIGN(InterceptedRequest);
+};
+
+InterceptedRequest::InterceptedRequest(int process_id, uint64_t request_id, int32_t routing_id, uint32_t options,
+ const network::ResourceRequest &request, const GURL &top_document_url,
+ const net::MutableNetworkTrafficAnnotationTag &traffic_annotation,
+ ProfileIODataQt *profileData,
+ network::mojom::URLLoaderRequest loader_request,
+ network::mojom::URLLoaderClientPtr client,
+ network::mojom::URLLoaderFactoryPtr target_factory)
+ : process_id_(process_id)
+ , request_id_(request_id)
+ , routing_id_(routing_id)
+ , options_(options)
+ , m_topDocumentUrl(top_document_url)
+ , request_(request)
+ , traffic_annotation_(traffic_annotation)
+ , m_profileData(profileData)
+ , proxied_loader_binding_(this, std::move(loader_request))
+ , target_client_(std::move(client))
+ , proxied_client_binding_(this)
+ , target_factory_(std::move(target_factory))
+ , m_weakFactory(this)
+ , m_weakPtr(m_weakFactory.GetWeakPtr())
+{
+ // If there is a client error, clean up the request.
+ target_client_.set_connection_error_handler(
+ base::BindOnce(&InterceptedRequest::OnURLLoaderClientError, m_weakFactory.GetWeakPtr()));
+ proxied_loader_binding_.set_connection_error_with_reason_handler(
+ base::BindOnce(&InterceptedRequest::OnURLLoaderError, m_weakFactory.GetWeakPtr()));
+}
+
+InterceptedRequest::~InterceptedRequest()
+{
+ m_weakFactory.InvalidateWeakPtrs();
+}
+
+void InterceptedRequest::Restart()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ content::ResourceType resourceType = content::ResourceType(request_.resource_type);
+ WebContentsAdapterClient::NavigationType navigationType =
+ pageTransitionToNavigationType(ui::PageTransition(request_.transition_type));
+
+ m_originalUrl = toQt(request_.url);
+
+ const QUrl initiator = request_.request_initiator.has_value() ? toQt(request_.request_initiator->GetURL()) : QUrl();
+
+ QUrl firstPartyUrl;
+ if (!m_topDocumentUrl.is_empty())
+ firstPartyUrl = toQt(m_topDocumentUrl);
+ else
+ firstPartyUrl = toQt(request_.site_for_cookies); // m_topDocumentUrl can be empty for the main-frame.
+
+ QWebEngineUrlRequestInfoPrivate *infoPrivate =
+ new QWebEngineUrlRequestInfoPrivate(toQt(resourceType), toQt(navigationType),
+ m_originalUrl, firstPartyUrl, initiator,
+ QByteArray::fromStdString(request_.method));
+ m_requestInfo = QWebEngineUrlRequestInfo(infoPrivate);
+
+ if (m_profileData && m_profileData->isInterceptorDeprecated()) {
+ QWebEngineUrlRequestInterceptor *interceptor = m_profileData->acquireInterceptor();
+ if (interceptor && m_profileData->isInterceptorDeprecated())
+ interceptor->interceptRequest(m_requestInfo);
+ m_profileData->releaseInterceptor();
+ }
+
+ if (m_requestInfo.changed()) {
+ ContinueAfterIntercept();
+ } else {
+ // FIXME: unretained post?
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(&InterceptedRequest::InterceptOnUIThread, base::Unretained(this)));
+ }
+}
+
+void InterceptedRequest::InterceptOnUIThread()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+
+ content::WebContents *webContents = nullptr;
+ if (process_id_) {
+ content::RenderFrameHost *frameHost = content::RenderFrameHost::FromID(process_id_, request_.render_frame_id);
+ webContents = content::WebContents::FromRenderFrameHost(frameHost);
+ } else
+ webContents = content::WebContents::FromFrameTreeNodeId(request_.render_frame_id);
+
+ if (webContents) {
+ if (m_profileData) {
+ QWebEngineUrlRequestInterceptor *interceptor = m_profileData->requestInterceptor();
+ if (interceptor && !interceptor->property("deprecated").toBool())
+ interceptor->interceptRequest(m_requestInfo);
+ }
+
+ WebContentsAdapterClient *client =
+ WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client();
+
+ if (!m_requestInfo.changed())
+ client->interceptRequest(m_requestInfo);
+ }
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&InterceptedRequest::ContinueAfterIntercept, m_weakPtr));
+}
+
+void InterceptedRequest::ContinueAfterIntercept()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ if (m_requestInfo.changed()) {
+ if (m_requestInfo.d_ptr->shouldBlockRequest)
+ return SendErrorAndCompleteImmediately(net::ERR_BLOCKED_BY_CLIENT);
+ if (m_requestInfo.requestUrl() != m_originalUrl) {
+ net::URLRequest::FirstPartyURLPolicy first_party_url_policy =
+ request_.update_first_party_url_on_redirect ? net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT
+ : net::URLRequest::NEVER_CHANGE_FIRST_PARTY_URL;
+ net::RedirectInfo redirectInfo = net::RedirectInfo::ComputeRedirectInfo(request_.method, request_.url,
+ request_.site_for_cookies,
+ first_party_url_policy, request_.referrer_policy,
+ request_.referrer.spec(), net::HTTP_TEMPORARY_REDIRECT,
+ toGurl(m_requestInfo.requestUrl()), base::nullopt,
+ false /*insecure_scheme_was_upgraded*/);
+
+ // FIXME: Should probably create a new header.
+ current_response_.encoded_data_length = 0;
+ request_.method = redirectInfo.new_method;
+ request_.url = redirectInfo.new_url;
+ request_.site_for_cookies = redirectInfo.new_site_for_cookies;
+ request_.referrer = GURL(redirectInfo.new_referrer);
+ request_.referrer_policy = redirectInfo.new_referrer_policy;
+ if (request_.method == net::HttpRequestHeaders::kGetMethod)
+ request_.request_body = nullptr;
+ target_client_->OnReceiveRedirect(redirectInfo, current_response_);
+ return;
+ }
+
+ if (!m_requestInfo.d_ptr->extraHeaders.isEmpty()) {
+ auto end = m_requestInfo.d_ptr->extraHeaders.constEnd();
+ for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header) {
+ std::string h = header.key().toStdString();
+ if (base::LowerCaseEqualsASCII(h, "referer")) {
+ request_.referrer = GURL(header.value().toStdString());
+ } else {
+ request_.headers.SetHeader(h, header.value().toStdString());
+ }
+ }
+ }
+ }
+
+ if (!target_loader_ && target_factory_) {
+ network::mojom::URLLoaderClientPtr proxied_client;
+ proxied_client_binding_.Bind(mojo::MakeRequest(&proxied_client));
+ target_factory_->CreateLoaderAndStart(mojo::MakeRequest(&target_loader_), routing_id_, request_id_, options_,
+ request_, std::move(proxied_client), traffic_annotation_);
+ }
+}
+
+// URLLoaderClient methods.
+
+void InterceptedRequest::OnReceiveResponse(network::mojom::URLResponseHeadPtr head)
+{
+ current_response_ = head;
+
+ target_client_->OnReceiveResponse(std::move(head));
+}
+
+void InterceptedRequest::OnReceiveRedirect(const net::RedirectInfo &redirect_info, network::mojom::URLResponseHeadPtr head)
+{
+ // TODO(timvolodine): handle redirect override.
+ request_was_redirected_ = true;
+ current_response_ = head;
+ target_client_->OnReceiveRedirect(redirect_info, std::move(head));
+ request_.url = redirect_info.new_url;
+ request_.method = redirect_info.new_method;
+ request_.site_for_cookies = redirect_info.new_site_for_cookies;
+ request_.referrer = GURL(redirect_info.new_referrer);
+ request_.referrer_policy = redirect_info.new_referrer_policy;
+}
+
+void InterceptedRequest::OnUploadProgress(int64_t current_position, int64_t total_size, OnUploadProgressCallback callback)
+{
+ target_client_->OnUploadProgress(current_position, total_size, std::move(callback));
+}
+
+void InterceptedRequest::OnReceiveCachedMetadata(mojo_base::BigBuffer data)
+{
+ target_client_->OnReceiveCachedMetadata(std::move(data));
+}
+
+void InterceptedRequest::OnTransferSizeUpdated(int32_t transfer_size_diff)
+{
+ target_client_->OnTransferSizeUpdated(transfer_size_diff);
+}
+
+void InterceptedRequest::OnStartLoadingResponseBody(mojo::ScopedDataPipeConsumerHandle body)
+{
+ target_client_->OnStartLoadingResponseBody(std::move(body));
+}
+
+void InterceptedRequest::OnComplete(const network::URLLoaderCompletionStatus &status)
+{
+ // Only wait for the original loader to possibly have a custom error if the
+ // target loader succeeded. If the target loader failed, then it was a race as
+ // to whether that error or the safe browsing error would be reported.
+ CallOnComplete(status, status.error_code == net::OK);
+}
+
+// URLLoader methods.
+
+void InterceptedRequest::FollowRedirect(const std::vector<std::string> &removed_headers,
+ const net::HttpRequestHeaders &modified_headers,
+ const base::Optional<GURL> &new_url)
+{
+ if (target_loader_)
+ target_loader_->FollowRedirect(removed_headers, modified_headers, new_url);
+
+ // If |OnURLLoaderClientError| was called then we're just waiting for the
+ // connection error handler of |proxied_loader_binding_|. Don't restart the
+ // job since that'll create another URLLoader
+ if (!target_client_)
+ return;
+
+ Restart();
+}
+
+void InterceptedRequest::SetPriority(net::RequestPriority priority, int32_t intra_priority_value)
+{
+ if (target_loader_)
+ target_loader_->SetPriority(priority, intra_priority_value);
+}
+
+void InterceptedRequest::PauseReadingBodyFromNet()
+{
+ if (target_loader_)
+ target_loader_->PauseReadingBodyFromNet();
+}
+
+void InterceptedRequest::ResumeReadingBodyFromNet()
+{
+ if (target_loader_)
+ target_loader_->ResumeReadingBodyFromNet();
+}
+
+void InterceptedRequest::OnURLLoaderClientError()
+{
+ // We set |wait_for_loader_error| to true because if the loader did have a
+ // custom_reason error then the client would be reset as well and it would be
+ // a race as to which connection error we saw first.
+ CallOnComplete(network::URLLoaderCompletionStatus(net::ERR_ABORTED), true /* wait_for_loader_error */);
+}
+
+void InterceptedRequest::OnURLLoaderError(uint32_t custom_reason, const std::string &description)
+{
+ // If CallOnComplete was already called, then this object is ready to be deleted.
+ if (!target_client_)
+ delete this;
+}
+
+void InterceptedRequest::CallOnComplete(const network::URLLoaderCompletionStatus &status, bool wait_for_loader_error)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ // Save an error status so that we call onReceiveError at destruction if there
+ // was no safe browsing error.
+ if (status.error_code != net::OK)
+ error_status_ = status.error_code;
+
+ if (target_client_)
+ target_client_->OnComplete(status);
+
+ if (proxied_loader_binding_ && wait_for_loader_error) {
+ // Don't delete |this| yet, in case the |proxied_loader_binding_|'s
+ // error_handler is called with a reason to indicate an error which we want
+ // to send to the client bridge. Also reset |target_client_| so we don't
+ // get its error_handler called and then delete |this|.
+ target_client_.reset();
+
+ // Since the original client is gone no need to continue loading the
+ // request.
+ proxied_client_binding_.Close();
+ target_loader_.reset();
+
+ // In case there are pending checks as to whether this request should be
+ // intercepted, we don't want that causing |target_client_| to be used
+ // later.
+ m_weakFactory.InvalidateWeakPtrs();
+ } else {
+ delete this;
+ }
+}
+
+void InterceptedRequest::SendErrorAndCompleteImmediately(int error_code)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ auto status = network::URLLoaderCompletionStatus(error_code);
+ target_client_->OnComplete(status);
+ delete this;
+}
+
+ProxyingURLLoaderFactoryQt::ProxyingURLLoaderFactoryQt(int process_id,
+ content::ResourceContext *resourceContext,
+ content::RenderFrameHostImpl *host,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info)
+ : m_processId(process_id), m_resourceContext(resourceContext), m_renderFrameHost(host), m_weakFactory(this)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ if (target_factory_info) {
+ m_targetFactory.Bind(std::move(target_factory_info));
+ m_targetFactory.set_connection_error_handler(
+ base::BindOnce(&ProxyingURLLoaderFactoryQt::OnTargetFactoryError, m_weakFactory.GetWeakPtr()));
+ }
+ m_proxyReceivers.Add(this, std::move(loader_receiver));
+ m_proxyReceivers.set_disconnect_handler(
+ base::BindRepeating(&ProxyingURLLoaderFactoryQt::OnProxyBindingError, m_weakFactory.GetWeakPtr()));
+}
+
+ProxyingURLLoaderFactoryQt::~ProxyingURLLoaderFactoryQt()
+{
+ m_weakFactory.InvalidateWeakPtrs();
+}
+
+// static
+void ProxyingURLLoaderFactoryQt::CreateProxy(int process_id,
+ content::ResourceContext *resourceContext,
+ content::RenderFrameHostImpl *host,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ // Will manage its own lifetime
+ new ProxyingURLLoaderFactoryQt(process_id, resourceContext, host, std::move(loader_receiver), std::move(target_factory_info));
+}
+
+void ProxyingURLLoaderFactoryQt::CreateLoaderAndStart(network::mojom::URLLoaderRequest loader, int32_t routing_id,
+ int32_t request_id, uint32_t options,
+ const network::ResourceRequest &request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag &traffic_annotation)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+
+ ProfileIODataQt *profileIOData = ProfileIODataQt::FromResourceContext(m_resourceContext);
+
+ QWebEngineUrlRequestInterceptor *profileInterceptor = profileIOData ? profileIOData->requestInterceptor() : nullptr;
+ if (!profileIOData || !(profileInterceptor || profileIOData->hasPageInterceptors())) {
+ m_targetFactory->CreateLoaderAndStart(
+ std::move(loader), routing_id, request_id, options, request,
+ std::move(client), traffic_annotation);
+ return;
+ }
+
+ network::mojom::URLLoaderFactoryPtr target_factory_clone;
+ if (m_targetFactory)
+ m_targetFactory->Clone(mojo::MakeRequest(&target_factory_clone));
+
+ // Follows a similar path to the root as RenderFrameHostImpl::CalculateSiteForCookies()
+ GURL top_document_url;
+ if (m_renderFrameHost)
+ top_document_url = m_renderFrameHost->frame_tree_node()->frame_tree()->root()->current_frame_host()->GetLastCommittedURL();
+ else
+ LOG(INFO) << "ProxyingURLLoaderFactoryQt::CreateLoaderAndStart() - null m_renderFrameHost, shouldn't happen";
+
+ // Will manage its own lifetime
+ InterceptedRequest *req = new InterceptedRequest(m_processId, request_id, routing_id, options, request,
+ top_document_url,
+ traffic_annotation, profileIOData,
+ std::move(loader), std::move(client),
+ std::move(target_factory_clone));
+ req->Restart();
+}
+
+void ProxyingURLLoaderFactoryQt::OnTargetFactoryError()
+{
+ delete this;
+}
+
+void ProxyingURLLoaderFactoryQt::OnProxyBindingError()
+{
+ if (m_proxyReceivers.empty())
+ delete this;
+}
+
+void ProxyingURLLoaderFactoryQt::Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ m_proxyReceivers.Add(this, std::move(receiver));
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/net/proxying_url_loader_factory_qt.h b/src/core/net/proxying_url_loader_factory_qt.h
new file mode 100644
index 000000000..4d913f545
--- /dev/null
+++ b/src/core/net/proxying_url_loader_factory_qt.h
@@ -0,0 +1,109 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef PROXYING_URL_LOADER_FACTORY_QT_H_
+#define PROXYING_URL_LOADER_FACTORY_QT_H_
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/ref_counted_delete_on_sequence.h"
+#include "base/memory/weak_ptr.h"
+#include "base/optional.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
+#include "net/traffic_annotation/network_traffic_annotation.h"
+#include "services/network/public/cpp/resource_request.h"
+#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "url/gurl.h"
+
+// based on aw_proxying_url_loader_factory.h:
+// Copyright 2018 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 file.
+
+namespace content {
+class RenderFrameHostImpl;
+class ResourceContext;
+}
+
+namespace QtWebEngineCore {
+
+class ProxyingURLLoaderFactoryQt : public network::mojom::URLLoaderFactory
+{
+public:
+ ProxyingURLLoaderFactoryQt(int process_id, content::ResourceContext *resourceContext,
+ content::RenderFrameHostImpl *host,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info);
+
+ ~ProxyingURLLoaderFactoryQt() override;
+
+ static void CreateProxy(int process_id, content::ResourceContext *resourceContext,
+ content::RenderFrameHostImpl *host,
+ mojo::PendingReceiver<network::mojom::URLLoaderFactory> loader_receiver,
+ network::mojom::URLLoaderFactoryPtrInfo target_factory_info);
+
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest loader, int32_t routing_id, int32_t request_id,
+ uint32_t options, const network::ResourceRequest &request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag &traffic_annotation) override;
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver) override;
+
+private:
+ void OnTargetFactoryError();
+ void OnProxyBindingError();
+
+ const int m_processId;
+ mojo::ReceiverSet<network::mojom::URLLoaderFactory> m_proxyReceivers;
+ network::mojom::URLLoaderFactoryPtr m_targetFactory;
+
+ content::ResourceContext *m_resourceContext;
+ content::RenderFrameHostImpl *m_renderFrameHost;
+
+ base::WeakPtrFactory<ProxyingURLLoaderFactoryQt> m_weakFactory;
+
+ DISALLOW_COPY_AND_ASSIGN(ProxyingURLLoaderFactoryQt);
+};
+
+} // namespace QtWebEngineCore
+
+#endif // PROXYING_URL_LOADER_FACTORY_QT_H_
diff --git a/src/core/net/restricted_cookie_manager_qt.cpp b/src/core/net/restricted_cookie_manager_qt.cpp
deleted file mode 100644
index 7f1ca163e..000000000
--- a/src/core/net/restricted_cookie_manager_qt.cpp
+++ /dev/null
@@ -1,185 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// originally based on android_webview/browser/network_service/aw_proxying_restricted_cookie_manager.cc:
-// Copyright 2019 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 file.
-
-#include "restricted_cookie_manager_qt.h"
-
-#include "api/qwebenginecookiestore.h"
-#include "api/qwebenginecookiestore_p.h"
-#include "profile_adapter.h"
-#include "profile_qt.h"
-#include "type_conversion.h"
-
-#include "base/memory/ptr_util.h"
-#include "base/task/post_task.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
-
-namespace QtWebEngineCore {
-
-class RestrictedCookieManagerListenerQt : public network::mojom::CookieChangeListener
-{
-public:
- RestrictedCookieManagerListenerQt(const GURL &url,
- const GURL &site_for_cookies,
- base::WeakPtr<RestrictedCookieManagerQt> restricted_cookie_manager,
- network::mojom::CookieChangeListenerPtr client_listener)
- : url_(url)
- , site_for_cookies_(site_for_cookies)
- , restricted_cookie_manager_(restricted_cookie_manager)
- , client_listener_(std::move(client_listener))
- {}
-
- void OnCookieChange(const net::CanonicalCookie &cookie, network::mojom::CookieChangeCause cause) override
- {
- if (restricted_cookie_manager_ && restricted_cookie_manager_->allowCookies(url_, site_for_cookies_))
- client_listener_->OnCookieChange(cookie, cause);
- }
-
-private:
- const GURL url_;
- const GURL site_for_cookies_;
- base::WeakPtr<RestrictedCookieManagerQt> restricted_cookie_manager_;
- network::mojom::CookieChangeListenerPtr client_listener_;
-};
-
-RestrictedCookieManagerQt::RestrictedCookieManagerQt(base::WeakPtr<ProfileIODataQt> profileIoData,
- network::mojom::RestrictedCookieManagerRole role,
- net::CookieStore *cookie_store,
- network::CookieSettings *cookie_settings,
- const url::Origin &origin,
- bool is_service_worker,
- int32_t process_id,
- int32_t frame_id)
- : network::RestrictedCookieManager(role, cookie_store, cookie_settings, origin,
- nullptr, is_service_worker, process_id, frame_id)
- , m_profileIoData(profileIoData)
- , weak_factory_(this)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-}
-
-RestrictedCookieManagerQt::~RestrictedCookieManagerQt()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-}
-
-void RestrictedCookieManagerQt::GetAllForUrl(const GURL &url,
- const GURL &site_for_cookies,
- network::mojom::CookieManagerGetOptionsPtr options,
- GetAllForUrlCallback callback)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- if (allowCookies(url, site_for_cookies)) {
- network::RestrictedCookieManager::GetAllForUrl(url, site_for_cookies, std::move(options), std::move(callback));
- } else {
- std::move(callback).Run(std::vector<net::CanonicalCookie>());
- }
-}
-
-void RestrictedCookieManagerQt::SetCanonicalCookie(const net::CanonicalCookie &cookie,
- const GURL &url,
- const GURL &site_for_cookies,
- SetCanonicalCookieCallback callback)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- if (allowCookies(url, site_for_cookies)) {
- network::RestrictedCookieManager::SetCanonicalCookie(cookie, url, site_for_cookies, std::move(callback));
- } else {
- std::move(callback).Run(false);
- }
-}
-
-void RestrictedCookieManagerQt::AddChangeListener(const GURL &url,
- const GURL &site_for_cookies,
- network::mojom::CookieChangeListenerPtr listener,
- AddChangeListenerCallback callback)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- network::mojom::CookieChangeListenerPtr proxy_listener_ptr;
- auto proxy_listener =
- std::make_unique<RestrictedCookieManagerListenerQt>(
- url, site_for_cookies, weak_factory_.GetWeakPtr(),
- std::move(listener));
-
- mojo::MakeStrongBinding(std::move(proxy_listener),
- mojo::MakeRequest(&proxy_listener_ptr));
-
- network::RestrictedCookieManager::AddChangeListener(
- url, site_for_cookies, std::move(proxy_listener_ptr),
- std::move(callback));
-}
-
-void RestrictedCookieManagerQt::GetCookiesString(const GURL &url,
- const GURL &site_for_cookies,
- GetCookiesStringCallback callback)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- if (allowCookies(url, site_for_cookies)) {
- network::RestrictedCookieManager::GetCookiesString(url, site_for_cookies, std::move(callback));
- } else {
- std::move(callback).Run("");
- }
-}
-
-void RestrictedCookieManagerQt::CookiesEnabledFor(const GURL &url,
- const GURL &site_for_cookies,
- CookiesEnabledForCallback callback)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- std::move(callback).Run(allowCookies(url, site_for_cookies));
-}
-
-bool RestrictedCookieManagerQt::allowCookies(const GURL &url, const GURL &site_for_cookies) const
-{
- if (!m_profileIoData)
- return false;
- return m_profileIoData->canGetCookies(toQt(site_for_cookies), toQt(url));
-}
-
-} // namespace QtWebEngineCore
diff --git a/src/core/net/ssl_host_state_delegate_qt.cpp b/src/core/net/ssl_host_state_delegate_qt.cpp
index 0885475be..f327717e9 100644
--- a/src/core/net/ssl_host_state_delegate_qt.cpp
+++ b/src/core/net/ssl_host_state_delegate_qt.cpp
@@ -105,8 +105,7 @@ void SSLHostStateDelegateQt::Clear(const base::Callback<bool(const std::string &
// prior to this query, otherwise false.
content::SSLHostStateDelegate::CertJudgment SSLHostStateDelegateQt::QueryPolicy(const std::string &host,
const net::X509Certificate &cert,
- int error,
- bool * /*expired_previous_decision*/)
+ int error)
{
return m_certPolicyforHost[host].Check(cert, error) ? SSLHostStateDelegate::ALLOWED : SSLHostStateDelegate::DENIED;
}
diff --git a/src/core/net/ssl_host_state_delegate_qt.h b/src/core/net/ssl_host_state_delegate_qt.h
index e361aa0be..b3b89f117 100644
--- a/src/core/net/ssl_host_state_delegate_qt.h
+++ b/src/core/net/ssl_host_state_delegate_qt.h
@@ -68,8 +68,7 @@ public:
// content::SSLHostStateDelegate implementation:
void AllowCert(const std::string &, const net::X509Certificate &cert, int error) override;
void Clear(const base::Callback<bool(const std::string &)> &host_filter) override;
- CertJudgment QueryPolicy(const std::string &host, const net::X509Certificate &cert, int error,
- bool *expired_previous_decision) override;
+ CertJudgment QueryPolicy(const std::string &host, const net::X509Certificate &cert, int error) override;
void HostRanInsecureContent(const std::string &host, int child_id, InsecureContentType content_type) override;
bool DidHostRunInsecureContent(const std::string &host, int child_id, InsecureContentType content_type) override;
void RevokeUserAllowExceptions(const std::string &host) override;
diff --git a/src/core/net/system_network_context_manager.cpp b/src/core/net/system_network_context_manager.cpp
new file mode 100644
index 000000000..2c5f49615
--- /dev/null
+++ b/src/core/net/system_network_context_manager.cpp
@@ -0,0 +1,350 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// based on chrome/browser/net/system_network_context_manager.cc:
+// Copyright 2017 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 file.
+
+#include "net/system_network_context_manager.h"
+
+#include <set>
+#include <unordered_map>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/feature_list.h"
+#include "base/logging.h"
+#include "base/sequence_checker.h"
+#include "base/strings/string_split.h"
+#include "base/task/post_task.h"
+#include "base/values.h"
+#include "build/build_config.h"
+#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
+#include "chrome/common/chrome_switches.h"
+#include "components/certificate_transparency/ct_known_logs.h"
+#include "components/network_session_configurator/common/network_features.h"
+#include "content/public/browser/browser_task_traits.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/cors_exempt_headers.h"
+#include "content/public/browser/network_service_instance.h"
+#include "content/public/common/content_features.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/service_names.mojom.h"
+#include "content/public/common/user_agent.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "net/dns/public/util.h"
+#include "net/net_buildflags.h"
+#include "net/third_party/uri_template/uri_template.h"
+#include "services/network/network_service.h"
+#include "services/network/public/cpp/cross_thread_shared_url_loader_factory_info.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/cpp/shared_url_loader_factory.h"
+#include "services/network/public/mojom/host_resolver.mojom.h"
+#include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+#include "url/gurl.h"
+
+namespace {
+
+// The global instance of the SystemNetworkContextmanager.
+SystemNetworkContextManager *g_system_network_context_manager = nullptr;
+
+network::mojom::HttpAuthStaticParamsPtr CreateHttpAuthStaticParams()
+{
+ network::mojom::HttpAuthStaticParamsPtr auth_static_params = network::mojom::HttpAuthStaticParams::New();
+
+ auth_static_params->supported_schemes = { "basic", "digest", "ntlm", "negotiate" };
+
+ return auth_static_params;
+}
+
+network::mojom::HttpAuthDynamicParamsPtr CreateHttpAuthDynamicParams()
+{
+ network::mojom::HttpAuthDynamicParamsPtr auth_dynamic_params = network::mojom::HttpAuthDynamicParams::New();
+
+ auto *command_line = base::CommandLine::ForCurrentProcess();
+ auth_dynamic_params->server_allowlist = command_line->GetSwitchValueASCII(switches::kAuthServerWhitelist);
+// auth_dynamic_params->delegate_allowlist = command_line->GetSwitchValueASCII(switches::kAuthNegotiateDelegateWhitelist);
+// auth_dynamic_params->enable_negotiate_port = command_line->HasSwitch(switches::kEnableAuthNegotiatePort);
+
+ return auth_dynamic_params;
+}
+
+} // namespace
+
+// SharedURLLoaderFactory backed by a SystemNetworkContextManager and its
+// network context. Transparently handles crashes.
+class SystemNetworkContextManager::URLLoaderFactoryForSystem : public network::SharedURLLoaderFactory
+{
+public:
+ explicit URLLoaderFactoryForSystem(SystemNetworkContextManager *manager) : manager_(manager)
+ {
+ DETACH_FROM_SEQUENCE(sequence_checker_);
+ }
+
+ // mojom::URLLoaderFactory implementation:
+
+ void CreateLoaderAndStart(network::mojom::URLLoaderRequest request, int32_t routing_id, int32_t request_id,
+ uint32_t options, const network::ResourceRequest &url_request,
+ network::mojom::URLLoaderClientPtr client,
+ const net::MutableNetworkTrafficAnnotationTag &traffic_annotation) override
+ {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ if (!manager_)
+ return;
+ manager_->GetURLLoaderFactory()->CreateLoaderAndStart(std::move(request), routing_id, request_id, options,
+ url_request, std::move(client), traffic_annotation);
+ }
+
+ void Clone(mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver)
+ {
+ if (!manager_)
+ return;
+ manager_->GetURLLoaderFactory()->Clone(std::move(receiver));
+ }
+
+ // SharedURLLoaderFactory implementation:
+ std::unique_ptr<network::SharedURLLoaderFactoryInfo> Clone() override
+ {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ return std::make_unique<network::CrossThreadSharedURLLoaderFactoryInfo>(this);
+ }
+
+ void Shutdown() { manager_ = nullptr; }
+
+private:
+ friend class base::RefCounted<URLLoaderFactoryForSystem>;
+ ~URLLoaderFactoryForSystem() override {}
+
+ SEQUENCE_CHECKER(sequence_checker_);
+ SystemNetworkContextManager *manager_;
+
+ DISALLOW_COPY_AND_ASSIGN(URLLoaderFactoryForSystem);
+};
+
+network::mojom::NetworkContext *SystemNetworkContextManager::GetContext()
+{
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ // SetUp should already have been called.
+ DCHECK(io_thread_network_context_);
+ return io_thread_network_context_.get();
+ }
+
+ if (!network_service_network_context_ || network_service_network_context_.encountered_error()) {
+ // This should call into OnNetworkServiceCreated(), which will re-create
+ // the network service, if needed. There's a chance that it won't be
+ // invoked, if the NetworkContext has encountered an error but the
+ // NetworkService has not yet noticed its pipe was closed. In that case,
+ // trying to create a new NetworkContext would fail, anyways, and hopefully
+ // a new NetworkContext will be created on the next GetContext() call.
+ content::GetNetworkService();
+ DCHECK(network_service_network_context_);
+ }
+ return network_service_network_context_.get();
+}
+
+network::mojom::URLLoaderFactory *SystemNetworkContextManager::GetURLLoaderFactory()
+{
+ // Create the URLLoaderFactory as needed.
+ if (url_loader_factory_ && !url_loader_factory_.encountered_error()) {
+ return url_loader_factory_.get();
+ }
+
+ network::mojom::URLLoaderFactoryParamsPtr params = network::mojom::URLLoaderFactoryParams::New();
+ params->process_id = network::mojom::kBrowserProcessId;
+ params->is_corb_enabled = false;
+ GetContext()->CreateURLLoaderFactory(mojo::MakeRequest(&url_loader_factory_), std::move(params));
+ return url_loader_factory_.get();
+}
+
+scoped_refptr<network::SharedURLLoaderFactory> SystemNetworkContextManager::GetSharedURLLoaderFactory()
+{
+ return shared_url_loader_factory_;
+}
+
+void SystemNetworkContextManager::SetUp(
+ network::mojom::NetworkContextRequest *network_context_request,
+ network::mojom::NetworkContextParamsPtr *network_context_params, bool *stub_resolver_enabled,
+ base::Optional<std::vector<network::mojom::DnsOverHttpsServerPtr>> *dns_over_https_servers,
+ network::mojom::HttpAuthStaticParamsPtr *http_auth_static_params,
+ network::mojom::HttpAuthDynamicParamsPtr *http_auth_dynamic_params, bool *is_quic_allowed)
+{
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) {
+ *network_context_request = mojo::MakeRequest(&io_thread_network_context_);
+ *network_context_params = CreateNetworkContextParams();
+ }
+ *is_quic_allowed = false;
+ *http_auth_static_params = CreateHttpAuthStaticParams();
+ *http_auth_dynamic_params = CreateHttpAuthDynamicParams();
+ // GetStubResolverConfig(local_state_, stub_resolver_enabled, dns_over_https_servers);
+}
+
+// static
+SystemNetworkContextManager *SystemNetworkContextManager::CreateInstance()
+{
+ DCHECK(!g_system_network_context_manager);
+ g_system_network_context_manager = new SystemNetworkContextManager();
+ return g_system_network_context_manager;
+}
+
+// static
+SystemNetworkContextManager *SystemNetworkContextManager::GetInstance()
+{
+ return g_system_network_context_manager;
+}
+
+// static
+void SystemNetworkContextManager::DeleteInstance()
+{
+ DCHECK(g_system_network_context_manager);
+ delete g_system_network_context_manager;
+}
+
+SystemNetworkContextManager::SystemNetworkContextManager()
+{
+ shared_url_loader_factory_ = new URLLoaderFactoryForSystem(this);
+}
+
+SystemNetworkContextManager::~SystemNetworkContextManager()
+{
+ shared_url_loader_factory_->Shutdown();
+}
+
+void SystemNetworkContextManager::OnNetworkServiceCreated(network::mojom::NetworkService *network_service)
+{
+ if (!base::FeatureList::IsEnabled(network::features::kNetworkService))
+ return;
+ // Disable QUIC globally
+ network_service->DisableQuic();
+
+ network_service->SetUpHttpAuth(CreateHttpAuthStaticParams());
+ network_service->ConfigureHttpAuthPrefs(CreateHttpAuthDynamicParams());
+
+ // The system NetworkContext must be created first, since it sets
+ // |primary_network_context| to true.
+ network_service->CreateNetworkContext(MakeRequest(&network_service_network_context_), CreateNetworkContextParams());
+
+ // 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;
+ // base::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));
+}
+
+void SystemNetworkContextManager::AddSSLConfigToNetworkContextParams(network::mojom::NetworkContextParams *network_context_params)
+{
+ network_context_params->initial_ssl_config = network::mojom::SSLConfig::New();
+ network_context_params->initial_ssl_config->rev_checking_enabled = true;
+ network_context_params->initial_ssl_config->symantec_enforcement_disabled = true;
+}
+
+network::mojom::NetworkContextParamsPtr SystemNetworkContextManager::CreateDefaultNetworkContextParams()
+{
+ network::mojom::NetworkContextParamsPtr network_context_params = network::mojom::NetworkContextParams::New();
+ content::UpdateCorsExemptHeader(network_context_params.get());
+
+ network_context_params->enable_brotli = true;
+
+ // network_context_params->user_agent = GetUserAgent();
+
+ // Disable referrers by default. Any consumer that enables referrers should
+ // respect prefs::kEnableReferrers from the appropriate pref store.
+ network_context_params->enable_referrers = false;
+
+ // const base::CommandLine& command_line =
+ // *base::CommandLine::ForCurrentProcess();
+
+ // // TODO(eroman): Figure out why this doesn't work in single-process mode,
+ // // or if it does work, now.
+ // // Should be possible now that a private isolate is used.
+ // // http://crbug.com/474654
+ // if (!command_line.HasSwitch(switches::kWinHttpProxyResolver)) {
+ // if (command_line.HasSwitch(switches::kSingleProcess)) {
+ // LOG(ERROR) << "Cannot use V8 Proxy resolver in single process mode.";
+ // } else {
+ network_context_params->proxy_resolver_factory = ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver();
+ // }
+ // }
+
+ // network_context_params->pac_quick_check_enabled = local_state_->GetBoolean(prefs::kQuickCheckEnabled);
+
+ // Use the SystemNetworkContextManager to populate and update SSL
+ // configuration. The SystemNetworkContextManager is owned by the
+ // BrowserProcess itself, so will only be destroyed on shutdown, at which
+ // point, all NetworkContexts will be destroyed as well.
+ AddSSLConfigToNetworkContextParams(network_context_params.get());
+
+ // CT is only enabled on Desktop platforms for now.
+ network_context_params->enforce_chrome_ct_policy = true;
+ for (const auto &ct_log : certificate_transparency::GetKnownLogs()) {
+ // TODO(rsleevi): https://crbug.com/702062 - Remove this duplication.
+ network::mojom::CTLogInfoPtr log_info = network::mojom::CTLogInfo::New();
+ log_info->public_key = std::string(ct_log.log_key, ct_log.log_key_length);
+ log_info->name = ct_log.log_name;
+ network_context_params->ct_logs.push_back(std::move(log_info));
+ }
+
+ return network_context_params;
+}
+
+network::mojom::NetworkContextParamsPtr SystemNetworkContextManager::CreateNetworkContextParams()
+{
+ // TODO(mmenke): Set up parameters here (in memory cookie store, etc).
+ network::mojom::NetworkContextParamsPtr network_context_params = CreateDefaultNetworkContextParams();
+
+ network_context_params->context_name = std::string("system");
+
+ network_context_params->enable_referrers = false;
+
+ network_context_params->http_cache_enabled = false;
+
+ // These are needed for PAC scripts that use FTP URLs.
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ network_context_params->enable_ftp_url_support = true;
+#endif
+
+ network_context_params->primary_network_context = false;
+
+ proxy_config_monitor_.AddToNetworkContextParams(network_context_params.get());
+
+ return network_context_params;
+}
diff --git a/src/core/net/system_network_context_manager.h b/src/core/net/system_network_context_manager.h
new file mode 100644
index 000000000..288af5195
--- /dev/null
+++ b/src/core/net/system_network_context_manager.h
@@ -0,0 +1,187 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// based on chrome/browser/net/system_network_context_manager.h:
+// Copyright 2017 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 file.
+
+#ifndef SYSTEM_NETWORK_CONTEXT_MANAGER_H_
+#define SYSTEM_NETWORK_CONTEXT_MANAGER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/optional.h"
+#include "services/network/public/mojom/host_resolver.mojom-forward.h"
+#include "services/network/public/mojom/network_context.mojom.h"
+#include "services/network/public/mojom/network_service.mojom-forward.h"
+#include "services/network/public/mojom/ssl_config.mojom-forward.h"
+#include "services/network/public/mojom/url_loader_factory.mojom-forward.h"
+
+#include "net/proxy_config_monitor.h"
+
+namespace network {
+namespace mojom {
+class URLLoaderFactory;
+}
+class SharedURLLoaderFactory;
+} // namespace network
+
+namespace net_log {
+class NetExportFileWriter;
+}
+
+// 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
+// cache, but it does have ephemeral cookie and channel ID stores. It also does
+// not have access to HTTP proxy auth information the user has entered or that
+// comes from extensions, and similarly, has no extension-provided per-profile
+// proxy configuration information.
+//
+// This class is also responsible for configuring global NetworkService state.
+//
+// The "system" NetworkContext will either share a URLRequestContext with
+// IOThread's SystemURLRequestContext and be part of IOThread's NetworkService
+// (If the network service is disabled) or be an independent NetworkContext
+// using the actual network service.
+//
+// This class is intended to eventually replace IOThread. Handling the two cases
+// differently allows this to be used in production without breaking anything or
+// requiring two separate paths, while IOThread consumers slowly transition over
+// to being compatible with the network service.
+class SystemNetworkContextManager
+{
+public:
+ ~SystemNetworkContextManager();
+
+ // Creates the global instance of SystemNetworkContextManager. If an
+ // instance already exists, this will cause a DCHECK failure.
+ static SystemNetworkContextManager *CreateInstance();
+
+ // Gets the global SystemNetworkContextManager instance.
+ static SystemNetworkContextManager *GetInstance();
+
+ // Destroys the global SystemNetworkContextManager instance.
+ static void DeleteInstance();
+
+ // If the network service is disabled, |network_context_request| will be for
+ // the NetworkContext used by the SystemNetworkContextManager and
+ // |network_context_params| as needed to set up a system NetworkContext.
+ // Otherwise, this method can still be used to help set up the IOThread's
+ // in-process URLRequestContext.
+ //
+ // Must be called before the system NetworkContext is first used.
+ //
+ // |stub_resolver_enabled|, |dns_over_https_servers|,
+ // |http_auth_static_params|, |http_auth_dynamic_params|, and
+ // |is_quic_allowed| are used to pass initial NetworkService state to the
+ // caller, so the NetworkService can be configured appropriately. Using
+ // NetworkService's Mojo interface to set those options would lead to races
+ // with other UI->IO thread network-related tasks, since Mojo doesn't preserve
+ // execution order relative to PostTasks.
+ void SetUp(network::mojom::NetworkContextRequest *network_context_request,
+ network::mojom::NetworkContextParamsPtr *network_context_params, bool *stub_resolver_enabled,
+ base::Optional<std::vector<network::mojom::DnsOverHttpsServerPtr>> *dns_over_https_servers,
+ network::mojom::HttpAuthStaticParamsPtr *http_auth_static_params,
+ network::mojom::HttpAuthDynamicParamsPtr *http_auth_dynamic_params, bool *is_quic_allowed);
+
+ // Returns the System NetworkContext. May only be called after SetUp(). Does
+ // any initialization of the NetworkService that may be needed when first
+ // called.
+ network::mojom::NetworkContext *GetContext();
+
+ // Returns a URLLoaderFactory owned by the SystemNetworkContextManager that is
+ // backed by the SystemNetworkContext. Allows sharing of the URLLoaderFactory.
+ // Prefer this to creating a new one. Call Clone() on the value returned by
+ // this method to get a URLLoaderFactory that can be used on other threads.
+ network::mojom::URLLoaderFactory *GetURLLoaderFactory();
+
+ // Returns a SharedURLLoaderFactory owned by the SystemNetworkContextManager
+ // that is backed by the SystemNetworkContext.
+ scoped_refptr<network::SharedURLLoaderFactory> GetSharedURLLoaderFactory();
+
+ // Called when content creates a NetworkService. Creates the
+ // SystemNetworkContext, if the network service is enabled.
+ void OnNetworkServiceCreated(network::mojom::NetworkService *network_service);
+
+ // Populates |initial_ssl_config| and |ssl_config_client_request| members of
+ // |network_context_params|. As long as the SystemNetworkContextManager
+ // exists, any NetworkContext created with the params will continue to get
+ // SSL configuration updates.
+ void AddSSLConfigToNetworkContextParams(network::mojom::NetworkContextParams *network_context_params);
+
+ // Returns default set of parameters for configuring the network service.
+ network::mojom::NetworkContextParamsPtr CreateDefaultNetworkContextParams();
+
+private:
+ class URLLoaderFactoryForSystem;
+
+ explicit SystemNetworkContextManager();
+
+ // Creates parameters for the NetworkContext. May only be called once, since
+ // it initializes some class members.
+ network::mojom::NetworkContextParamsPtr CreateNetworkContextParams();
+
+ // ProxyConfigMonitor proxy_config_monitor_;
+
+ // NetworkContext using the network service, if the network service is
+ // enabled. nullptr, otherwise.
+ network::mojom::NetworkContextPtr network_service_network_context_;
+
+ // This is a NetworkContext that wraps the IOThread's SystemURLRequestContext.
+ // Always initialized in SetUp, but it's only returned by Context() when the
+ // network service is disabled.
+ network::mojom::NetworkContextPtr io_thread_network_context_;
+
+ // URLLoaderFactory backed by the NetworkContext returned by GetContext(), so
+ // consumers don't all need to create their own factory.
+ scoped_refptr<URLLoaderFactoryForSystem> shared_url_loader_factory_;
+ network::mojom::URLLoaderFactoryPtr url_loader_factory_;
+
+ ProxyConfigMonitor proxy_config_monitor_;
+
+ DISALLOW_COPY_AND_ASSIGN(SystemNetworkContextManager);
+};
+
+#endif // SYSTEM_NETWORK_CONTEXT_MANAGER_H_
diff --git a/src/core/net/url_request_custom_job.cpp b/src/core/net/url_request_custom_job.cpp
deleted file mode 100644
index 0d4ac620f..000000000
--- a/src/core/net/url_request_custom_job.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "url_request_custom_job.h"
-#include "url_request_custom_job_proxy.h"
-
-#include "api/qwebengineurlscheme.h"
-
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/base/io_buffer.h"
-#include "net/http/http_util.h"
-
-#include <QIODevice>
-
-using namespace net;
-
-namespace QtWebEngineCore {
-
-URLRequestCustomJob::URLRequestCustomJob(URLRequest *request,
- NetworkDelegate *networkDelegate,
- const std::string &scheme,
- QPointer<ProfileAdapter> profileAdapter)
- : URLRequestJob(request, networkDelegate)
- , m_proxy(new URLRequestCustomJobProxy(this, scheme, profileAdapter))
- , m_device(nullptr)
- , m_firstBytePosition(0)
- , m_error(0)
- , m_pendingReadSize(0)
- , m_pendingReadPos(0)
- , m_pendingReadBuffer(nullptr)
- , m_corsEnabled(QWebEngineUrlScheme::schemeByName(QByteArray::fromStdString(scheme))
- .flags().testFlag(QWebEngineUrlScheme::CorsEnabled))
-{
-}
-
-URLRequestCustomJob::~URLRequestCustomJob()
-{
- m_proxy->m_job = nullptr;
- if (m_device && m_device->isOpen())
- m_device->close();
- m_device = nullptr;
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&URLRequestCustomJobProxy::release, m_proxy));
-}
-
-void URLRequestCustomJob::Start()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- HttpRequestHeaders requestHeaders = request()->extra_request_headers();
- std::map<std::string, std::string> headers;
- net::HttpRequestHeaders::Iterator it(requestHeaders);
- while (it.GetNext())
- headers.emplace(it.name(), it.value());
- if (!request()->referrer().empty())
- headers.emplace("Referer", request()->referrer());
-
- // TODO: handle UploadDataStream, for instance using a QIODevice wrapper.
-
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&URLRequestCustomJobProxy::initialize,
- m_proxy,
- request()->url(),
- request()->method(),
- request()->initiator(),
- std::move(headers)));
-}
-
-void URLRequestCustomJob::Kill()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- m_proxy->m_job = nullptr;
- if (m_device && m_device->isOpen())
- m_device->close();
- if (m_pendingReadBuffer) {
- m_pendingReadBuffer->Release();
- m_pendingReadBuffer = nullptr;
- m_pendingReadSize = 0;
- m_pendingReadPos = 0;
- }
- m_device = nullptr;
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&URLRequestCustomJobProxy::release,
- m_proxy));
- URLRequestJob::Kill();
-}
-
-bool URLRequestCustomJob::GetMimeType(std::string *mimeType) const
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (m_mimeType.size() > 0) {
- *mimeType = m_mimeType;
- return true;
- }
- return false;
-}
-
-bool URLRequestCustomJob::GetCharset(std::string *charset)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (m_charset.size() > 0) {
- *charset = m_charset;
- return true;
- }
- return false;
-}
-
-void URLRequestCustomJob::GetResponseInfo(HttpResponseInfo *info)
-{
- // Based on net::URLRequestRedirectJob::StartAsync()
-
- if (m_error)
- return;
-
- std::string headers;
- if (m_redirect.is_valid()) {
- headers += "HTTP/1.1 303 See Other\n";
- headers += base::StringPrintf("Location: %s\n", m_redirect.spec().c_str());
- } else {
- headers += base::StringPrintf("HTTP/1.1 %i OK\n", 200);
- if (m_mimeType.size() > 0) {
- headers += base::StringPrintf("Content-Type: %s", m_mimeType.c_str());
- if (m_charset.size() > 0)
- headers += base::StringPrintf("; charset=%s", m_charset.c_str());
- headers += "\n";
- }
- }
- if (m_corsEnabled) {
- std::string origin;
- if (request_->extra_request_headers().GetHeader("Origin", &origin)) {
- headers += base::StringPrintf("Access-Control-Allow-Origin: %s\n", origin.c_str());
- headers += "Access-Control-Allow-Credentials: true\n";
- }
- }
-
- info->headers = new HttpResponseHeaders(HttpUtil::AssembleRawHeaders(headers));
-}
-
-bool URLRequestCustomJob::IsRedirectResponse(GURL *location, int *http_status_code, bool * /*insecure_scheme_was_upgraded*/)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (m_redirect.is_valid()) {
- *location = m_redirect;
- *http_status_code = 303;
- return true;
- }
- return false;
-}
-
-void URLRequestCustomJob::SetExtraRequestHeaders(const HttpRequestHeaders &headers)
-{
- std::string rangeHeader;
- if (headers.GetHeader(HttpRequestHeaders::kRange, &rangeHeader)) {
- std::vector<HttpByteRange> ranges;
- if (HttpUtil::ParseRangeHeader(rangeHeader, &ranges)) {
- // Chromium doesn't support multiple range requests in one single URL request.
- if (ranges.size() == 1)
- m_firstBytePosition = ranges[0].first_byte_position();
- }
- }
-}
-
-int URLRequestCustomJob::ReadRawData(IOBuffer *buf, int bufSize)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (m_error)
- return m_error;
- qint64 rv = m_device ? m_device->read(buf->data(), bufSize) : -1;
- if (rv > 0) {
- return static_cast<int>(rv);
- } else if (rv == 0) {
- // Returning zero is interpreted as EOF by Chromium, so only
- // return zero if we are the end of the file.
- if (m_device->atEnd())
- return 0;
- // Otherwise return IO_PENDING and call ReadRawDataComplete when we have data
- // for them.
- buf->AddRef();
- m_pendingReadPos = 0;
- m_pendingReadSize = bufSize;
- m_pendingReadBuffer = buf;
- return ERR_IO_PENDING;
- } else {
- // QIODevice::read might have called fail on us.
- if (m_error)
- return m_error;
- if (m_device && m_device->atEnd())
- return 0;
- return ERR_FAILED;
- }
-}
-
-void URLRequestCustomJob::notifyReadyRead()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (!m_device)
- return;
- if (!m_pendingReadSize)
- return;
- Q_ASSERT(m_pendingReadBuffer);
- if (!m_pendingReadBuffer)
- return;
-
- qint64 rv = m_device->read(m_pendingReadBuffer->data() + m_pendingReadPos, m_pendingReadSize - m_pendingReadPos);
- if (rv == 0)
- return;
- if (rv < 0) {
- if (m_error)
- rv = m_error;
- else if (m_device->atEnd())
- rv = 0;
- else
- rv = ERR_FAILED;
- } else {
- m_pendingReadPos += rv;
- if (m_pendingReadPos < m_pendingReadSize && !m_device->atEnd())
- return;
- rv = m_pendingReadPos;
- }
- // killJob may be called from ReadRawDataComplete
- net::IOBuffer *buf = m_pendingReadBuffer;
- m_pendingReadBuffer = nullptr;
- m_pendingReadSize = 0;
- m_pendingReadPos = 0;
- ReadRawDataComplete(rv);
- buf->Release();
-}
-
-} // namespace
diff --git a/src/core/net/url_request_custom_job.h b/src/core/net/url_request_custom_job.h
deleted file mode 100644
index db40b52bb..000000000
--- a/src/core/net/url_request_custom_job.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef URL_REQUEST_CUSTOM_JOB_H_
-#define URL_REQUEST_CUSTOM_JOB_H_
-
-#include "net/url_request/url_request_job.h"
-#include "url/gurl.h"
-#include <QtCore/QPointer>
-
-QT_FORWARD_DECLARE_CLASS(QIODevice)
-
-namespace QtWebEngineCore {
-
-class ProfileAdapter;
-class URLRequestCustomJobDelegate;
-class URLRequestCustomJobProxy;
-
-// A request job that handles reading custom URL schemes
-class URLRequestCustomJob : public net::URLRequestJob
-{
-public:
- URLRequestCustomJob(net::URLRequest *request,
- net::NetworkDelegate *networkDelegate,
- const std::string &scheme,
- QPointer<ProfileAdapter> profileAdapter);
- void Start() override;
- void Kill() override;
- int ReadRawData(net::IOBuffer *buf, int buf_size) override;
- bool GetMimeType(std::string *mimeType) const override;
- bool GetCharset(std::string *charset) override;
- void GetResponseInfo(net::HttpResponseInfo *info) override;
- bool IsRedirectResponse(GURL *location, int *http_status_code, bool *insecure_scheme_was_upgraded) override;
- void SetExtraRequestHeaders(const net::HttpRequestHeaders &headers);
-
-protected:
- virtual ~URLRequestCustomJob();
-
-private:
- void notifyReadyRead();
- scoped_refptr<URLRequestCustomJobProxy> m_proxy;
- std::string m_mimeType;
- std::string m_charset;
- GURL m_redirect;
- QIODevice *m_device;
- int64_t m_firstBytePosition;
- int m_error;
- int m_pendingReadSize;
- int m_pendingReadPos;
- net::IOBuffer *m_pendingReadBuffer;
- const bool m_corsEnabled;
-
- friend class URLRequestCustomJobProxy;
-
- DISALLOW_COPY_AND_ASSIGN(URLRequestCustomJob);
-};
-} // namespace QtWebEngineCore
-
-#endif // URL_REQUEST_CUSTOM_JOB_H_
diff --git a/src/core/net/url_request_custom_job_delegate.cpp b/src/core/net/url_request_custom_job_delegate.cpp
index f73296cf0..ff307bede 100644
--- a/src/core/net/url_request_custom_job_delegate.cpp
+++ b/src/core/net/url_request_custom_job_delegate.cpp
@@ -92,27 +92,27 @@ void URLRequestCustomJobDelegate::reply(const QByteArray &contentType, QIODevice
{
if (device)
QObject::connect(device, &QIODevice::readyRead, this, &URLRequestCustomJobDelegate::slotReadyRead);
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&URLRequestCustomJobProxy::reply,
- m_proxy,contentType.toStdString(),device));
+ m_proxy->m_ioTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::reply,
+ m_proxy, contentType.toStdString(),device));
}
void URLRequestCustomJobDelegate::slotReadyRead()
{
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&URLRequestCustomJobProxy::readyRead, m_proxy));
+ m_proxy->m_ioTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::readyRead, m_proxy));
}
void URLRequestCustomJobDelegate::abort()
{
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&URLRequestCustomJobProxy::abort, m_proxy));
+ m_proxy->m_ioTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::abort, m_proxy));
}
void URLRequestCustomJobDelegate::redirect(const QUrl &url)
{
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&URLRequestCustomJobProxy::redirect, m_proxy, toGurl(url)));
+ m_proxy->m_ioTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::redirect, m_proxy, toGurl(url)));
}
void URLRequestCustomJobDelegate::fail(Error error)
@@ -138,8 +138,8 @@ void URLRequestCustomJobDelegate::fail(Error error)
break;
}
if (net_error) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&URLRequestCustomJobProxy::fail, m_proxy, net_error));
+ m_proxy->m_ioTaskRunner->PostTask(FROM_HERE,
+ base::BindOnce(&URLRequestCustomJobProxy::fail, m_proxy, net_error));
}
}
diff --git a/src/core/net/url_request_custom_job_proxy.cpp b/src/core/net/url_request_custom_job_proxy.cpp
index 27fed7bf2..f734db645 100644
--- a/src/core/net/url_request_custom_job_proxy.cpp
+++ b/src/core/net/url_request_custom_job_proxy.cpp
@@ -38,28 +38,29 @@
****************************************************************************/
#include "url_request_custom_job_proxy.h"
-#include "url_request_custom_job.h"
#include "url_request_custom_job_delegate.h"
+
+#include "content/public/browser/browser_thread.h"
+#include "net/base/net_errors.h"
+
#include "api/qwebengineurlrequestjob.h"
#include "profile_adapter.h"
#include "type_conversion.h"
-#include "content/public/browser/browser_thread.h"
#include "web_engine_context.h"
-using namespace net;
-
namespace QtWebEngineCore {
-URLRequestCustomJobProxy::URLRequestCustomJobProxy(URLRequestCustomJob *job,
+URLRequestCustomJobProxy::URLRequestCustomJobProxy(URLRequestCustomJobProxy::Client *client,
const std::string &scheme,
QPointer<ProfileAdapter> profileAdapter)
- : m_job(job)
+ : m_client(client)
, m_started(false)
, m_scheme(scheme)
, m_delegate(nullptr)
, m_profileAdapter(profileAdapter)
+ , m_ioTaskRunner(m_client->taskRunner())
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ DCHECK(m_ioTaskRunner && m_ioTaskRunner->RunsTasksInCurrentSequence());
}
URLRequestCustomJobProxy::~URLRequestCustomJobProxy()
@@ -87,74 +88,73 @@ void URLRequestCustomJobProxy::setReplyCharset(const std::string &charset)
*/
void URLRequestCustomJobProxy::reply(std::string mimeType, QIODevice *device)
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (!m_job)
+ if (!m_client)
return;
- m_job->m_mimeType = mimeType;
- m_job->m_device = device;
- if (m_job->m_device && !m_job->m_device->isReadable())
- m_job->m_device->open(QIODevice::ReadOnly);
+ DCHECK (!m_ioTaskRunner || m_ioTaskRunner->RunsTasksInCurrentSequence());
+ m_client->m_mimeType = mimeType;
+ m_client->m_device = device;
+ if (m_client->m_device && !m_client->m_device->isReadable())
+ m_client->m_device->open(QIODevice::ReadOnly);
- if (m_job->m_firstBytePosition > 0)
- m_job->m_device->seek(m_job->m_firstBytePosition);
+ if (m_client->m_firstBytePosition > 0)
+ m_client->m_device->seek(m_client->m_firstBytePosition);
- qint64 deviceSize = m_job->m_device ? m_job->m_device->size() : -1;
- qint64 remainingBytes = deviceSize - m_job->m_firstBytePosition;
- if (remainingBytes > 0)
- m_job->set_expected_content_size(remainingBytes);
+ qint64 deviceSize = m_client->m_device ? m_client->m_device->size() : -1;
+ if (deviceSize > 0)
+ m_client->notifyExpectedContentSize(deviceSize);
- if (m_job->m_device && m_job->m_device->isReadable()) {
+ if (m_client->m_device && m_client->m_device->isReadable()) {
m_started = true;
- m_job->NotifyHeadersComplete();
+ m_client->notifyHeadersComplete();
} else {
- fail(ERR_INVALID_URL);
+ fail(net::ERR_INVALID_URL);
}
}
void URLRequestCustomJobProxy::redirect(GURL url)
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (!m_job)
+ if (!m_client)
return;
- if (m_job->m_device || m_job->m_error)
+ DCHECK (!m_ioTaskRunner || m_ioTaskRunner->RunsTasksInCurrentSequence());
+ if (m_client->m_device || m_client->m_error)
return;
- m_job->m_redirect = url;
+ m_client->m_redirect = url;
m_started = true;
- m_job->NotifyHeadersComplete();
+ m_client->notifyHeadersComplete();
}
void URLRequestCustomJobProxy::abort()
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (!m_job)
+ if (!m_client)
return;
- if (m_job->m_device && m_job->m_device->isOpen())
- m_job->m_device->close();
- m_job->m_device = nullptr;
+ DCHECK (!m_ioTaskRunner || m_ioTaskRunner->RunsTasksInCurrentSequence());
+ if (m_client->m_device && m_client->m_device->isOpen())
+ m_client->m_device->close();
+ m_client->m_device = nullptr;
if (m_started)
- m_job->NotifyCanceled();
+ m_client->notifyCanceled();
else
- m_job->NotifyStartError(URLRequestStatus(URLRequestStatus::CANCELED, ERR_ABORTED));
+ m_client->notifyAborted();
}
void URLRequestCustomJobProxy::fail(int error)
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (!m_job)
+ if (!m_client)
return;
- m_job->m_error = error;
- if (m_job->m_device)
- m_job->m_device->close();
+ DCHECK (m_ioTaskRunner->RunsTasksInCurrentSequence());
+ m_client->m_error = error;
+ if (m_client->m_device)
+ m_client->m_device->close();
if (!m_started)
- m_job->NotifyStartError(URLRequestStatus::FromError(error));
+ m_client->notifyStartFailure(error);
// else we fail on the next read, or the read that might already be in progress
}
void URLRequestCustomJobProxy::readyRead()
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (m_job)
- m_job->notifyReadyRead();
+ DCHECK (m_ioTaskRunner->RunsTasksInCurrentSequence());
+ if (m_client)
+ m_client->notifyReadyRead();
}
void URLRequestCustomJobProxy::initialize(GURL url, std::string method,
diff --git a/src/core/net/url_request_custom_job_proxy.h b/src/core/net/url_request_custom_job_proxy.h
index d4cd7e208..db38083dd 100644
--- a/src/core/net/url_request_custom_job_proxy.h
+++ b/src/core/net/url_request_custom_job_proxy.h
@@ -42,6 +42,7 @@
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
+#include "base/task_runner.h"
#include "url/gurl.h"
#include "url/origin.h"
#include <QtCore/QPointer>
@@ -60,7 +61,24 @@ class URLRequestCustomJobProxy : public base::RefCountedThreadSafe<URLRequestCus
{
public:
- URLRequestCustomJobProxy(URLRequestCustomJob *job,
+ class Client {
+ public:
+ std::string m_mimeType;
+ std::string m_charset;
+ GURL m_redirect;
+ QIODevice *m_device;
+ int64_t m_firstBytePosition;
+ int m_error;
+ virtual void notifyExpectedContentSize(qint64 size) = 0;
+ virtual void notifyHeadersComplete() = 0;
+ virtual void notifyCanceled() = 0;
+ virtual void notifyAborted() = 0;
+ virtual void notifyStartFailure(int) = 0;
+ virtual void notifyReadyRead() = 0;
+ virtual base::TaskRunner *taskRunner() = 0;
+ };
+
+ URLRequestCustomJobProxy(Client *client,
const std::string &scheme,
QPointer<ProfileAdapter> profileAdapter);
~URLRequestCustomJobProxy();
@@ -76,13 +94,14 @@ public:
void readyRead();
// IO thread owned:
- URLRequestCustomJob *m_job;
+ Client *m_client;
bool m_started;
// UI thread owned:
std::string m_scheme;
URLRequestCustomJobDelegate *m_delegate;
QPointer<ProfileAdapter> m_profileAdapter;
+ scoped_refptr<base::TaskRunner> m_ioTaskRunner;
};
} // namespace QtWebEngineCore
diff --git a/src/core/net/url_request_notification.cpp b/src/core/net/url_request_notification.cpp
deleted file mode 100644
index 279bd5077..000000000
--- a/src/core/net/url_request_notification.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "url_request_notification.h"
-
-#include "base/supports_user_data.h"
-#include "base/task/post_task.h"
-#include "content/browser/web_contents/web_contents_impl.h"
-#include "content/public/browser/browser_thread.h"
-#include "net/url_request/url_request.h"
-#include "web_contents_adapter_client.h"
-#include "web_contents_view_qt.h"
-#include "profile_io_data_qt.h"
-#include "qwebengineurlrequestinfo_p.h"
-#include "type_conversion.h"
-#include <QVariant>
-
-namespace QtWebEngineCore {
-
-// Calls cancel() when the URLRequest is destroyed.
-class UserData : public base::SupportsUserData::Data
-{
-public:
- UserData(URLRequestNotification *ptr) : m_ptr(ptr) {}
- ~UserData() { m_ptr->cancel(); }
- static const char key[];
-
-private:
- URLRequestNotification *m_ptr;
-};
-
-const char UserData::key[] = "QtWebEngineCore::URLRequestNotification";
-
-static content::ResourceType fromQt(QWebEngineUrlRequestInfo::ResourceType resourceType)
-{
- return static_cast<content::ResourceType>(resourceType);
-}
-
-URLRequestNotification::URLRequestNotification(net::URLRequest *request, bool isMainFrameRequest, GURL *newUrl,
- QWebEngineUrlRequestInfo &&requestInfo,
- content::ResourceRequestInfo::WebContentsGetter webContentsGetter,
- net::CompletionOnceCallback callback, QPointer<ProfileAdapter> adapter)
- : m_request(request)
- , m_isMainFrameRequest(isMainFrameRequest)
- , m_newUrl(newUrl)
- , m_originalUrl(requestInfo.requestUrl())
- , m_requestInfo(std::move(requestInfo))
- , m_webContentsGetter(webContentsGetter)
- , m_callback(std::move(callback))
- , m_profileAdapter(adapter)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- m_request->SetUserData(UserData::key, std::make_unique<UserData>(this));
-
- base::PostTaskWithTraits(
- FROM_HERE,
- {content::BrowserThread::UI},
- base::BindOnce(&URLRequestNotification::notify, base::Unretained(this)));
-}
-
-
-void URLRequestNotification::notify()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
- // May run concurrently with cancel() so no peeking at m_request here.
-
- int result = net::OK;
- content::WebContents *webContents = m_webContentsGetter.Run();
-
- if (webContents) {
-
- if (m_profileAdapter && m_profileAdapter->requestInterceptor()) {
- QWebEngineUrlRequestInterceptor *interceptor = m_profileAdapter->requestInterceptor();
- if (!interceptor->property("deprecated").toBool())
- interceptor->interceptRequest(m_requestInfo);
- }
-
- WebContentsAdapterClient *client =
- WebContentsViewQt::from(static_cast<content::WebContentsImpl*>(webContents)->GetView())->client();
-
- if (!m_requestInfo.changed()) {
- client->interceptRequest(m_requestInfo);
- }
-
- if (m_requestInfo.changed()) {
- result = m_requestInfo.d_ptr->shouldBlockRequest ? net::ERR_BLOCKED_BY_CLIENT : net::OK;
- // We handle the rest of the changes later when we are back in I/O thread
- }
-
- // Only do navigationRequested on MAIN_FRAME and SUB_FRAME resources
- if (result == net::OK && content::IsResourceTypeFrame(fromQt(m_requestInfo.resourceType()))) {
- int navigationRequestAction = WebContentsAdapterClient::AcceptRequest;
- client->navigationRequested(m_requestInfo.navigationType(),
- m_requestInfo.requestUrl(),
- navigationRequestAction,
- m_isMainFrameRequest);
- result = net::ERR_FAILED;
- switch (static_cast<WebContentsAdapterClient::NavigationRequestAction>(navigationRequestAction)) {
- case WebContentsAdapterClient::AcceptRequest:
- result = net::OK;
- break;
- case WebContentsAdapterClient::IgnoreRequest:
- result = net::ERR_ABORTED;
- break;
- }
- DCHECK(result != net::ERR_FAILED);
- }
- }
-
- // Run the callback on the IO thread.
- base::PostTaskWithTraits(
- FROM_HERE,
- {content::BrowserThread::IO},
- base::BindOnce(&URLRequestNotification::complete, base::Unretained(this), result));
-}
-
-void URLRequestNotification::cancel()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- // May run concurrently with notify() but we only touch m_request here.
-
- m_request = nullptr;
-}
-
-void URLRequestNotification::complete(int error)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
-
- if (m_request) {
- if (m_requestInfo.changed()) {
- if (m_originalUrl != m_requestInfo.d_ptr->url)
- *m_newUrl = toGurl(m_requestInfo.d_ptr->url);
-
- if (!m_requestInfo.d_ptr->extraHeaders.isEmpty()) {
- auto end = m_requestInfo.d_ptr->extraHeaders.constEnd();
- for (auto header = m_requestInfo.d_ptr->extraHeaders.constBegin(); header != end; ++header) {
- std::string h = header.key().toStdString();
- if (base::LowerCaseEqualsASCII(h, "referer")) {
- m_request->SetReferrer(header.value().toStdString());
- } else {
- m_request->SetExtraRequestHeaderByName(h, header.value().toStdString(), /* overwrite */ true);
- }
- }
- }
- }
-
- if (m_request->status().status() != net::URLRequestStatus::CANCELED)
- std::move(m_callback).Run(error);
- m_request->RemoveUserData(UserData::key);
- }
-
- delete this;
-}
-
-}
diff --git a/src/core/net/webui_controller_factory_qt.cpp b/src/core/net/webui_controller_factory_qt.cpp
index 8c045bb7b..27e58d75f 100644
--- a/src/core/net/webui_controller_factory_qt.cpp
+++ b/src/core/net/webui_controller_factory_qt.cpp
@@ -65,7 +65,7 @@
#include "url/gurl.h"
#if defined(OS_LINUX) || defined(OS_ANDROID)
-#include "chrome/browser/ui/webui/sandbox_internals_ui.h"
+#include "chrome/browser/ui/webui/sandbox/sandbox_internals_ui.h"
#endif
// The Following WebUIs are disabled because they currently doesn't build
diff --git a/src/core/ozone/gl_surface_qt.cpp b/src/core/ozone/gl_surface_qt.cpp
index e9da5e6a5..c54a8f12e 100644
--- a/src/core/ozone/gl_surface_qt.cpp
+++ b/src/core/ozone/gl_surface_qt.cpp
@@ -238,6 +238,11 @@ bool DirectCompositionSurfaceWin::IsHDRSupported()
{
return false;
}
+
+bool DirectCompositionSurfaceWin::IsSwapChainTearingSupported()
+{
+ return false;
+}
} // namespace gl
#endif
#endif // !defined(OS_MACOSX)
diff --git a/src/core/ozone/ozone_platform_qt.cpp b/src/core/ozone/ozone_platform_qt.cpp
index 2ab274b8f..887bc167e 100644
--- a/src/core/ozone/ozone_platform_qt.cpp
+++ b/src/core/ozone/ozone_platform_qt.cpp
@@ -51,7 +51,6 @@
#include "ui/ozone/public/system_input_injector.h"
#include "ui/platform_window/platform_window_delegate.h"
#include "ui/platform_window/platform_window_init_properties.h"
-#include "ui/platform_window/platform_window.h"
#include "surface_factory_qt.h"
#include "platform_window_qt.h"
@@ -68,7 +67,7 @@ public:
ui::SurfaceFactoryOzone* GetSurfaceFactoryOzone() override;
ui::CursorFactoryOzone* GetCursorFactoryOzone() override;
GpuPlatformSupportHost* GetGpuPlatformSupportHost() override;
- std::unique_ptr<PlatformWindow> CreatePlatformWindow(PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties) override;
+ std::unique_ptr<PlatformWindowBase> CreatePlatformWindow(PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties) override;
std::unique_ptr<display::NativeDisplayDelegate> CreateNativeDisplayDelegate() override;
ui::InputController* GetInputController() override;
std::unique_ptr<ui::SystemInputInjector> CreateSystemInputInjector() override;
@@ -109,7 +108,7 @@ GpuPlatformSupportHost* OzonePlatformQt::GetGpuPlatformSupportHost()
return gpu_platform_support_host_.get();
}
-std::unique_ptr<PlatformWindow> OzonePlatformQt::CreatePlatformWindow(PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties)
+std::unique_ptr<PlatformWindowBase> OzonePlatformQt::CreatePlatformWindow(PlatformWindowDelegate* delegate, PlatformWindowInitProperties properties)
{
return base::WrapUnique(new PlatformWindowQt(delegate, properties.bounds));
}
diff --git a/src/core/ozone/platform_window_qt.h b/src/core/ozone/platform_window_qt.h
index ca4a00313..344e9b115 100644
--- a/src/core/ozone/platform_window_qt.h
+++ b/src/core/ozone/platform_window_qt.h
@@ -45,13 +45,12 @@
#include "ui/events/platform/platform_event_dispatcher.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/rect.h"
-#include "ui/platform_window/platform_window.h"
+#include "ui/platform_window/platform_window_base.h"
+#include "ui/platform_window/platform_window_delegate.h"
namespace ui {
-class PlatformWindowDelegate;
-
-class PlatformWindowQt : public PlatformWindow, public PlatformEventDispatcher
+class PlatformWindowQt : public PlatformWindowBase, public PlatformEventDispatcher
{
public:
PlatformWindowQt(PlatformWindowDelegate* delegate, const gfx::Rect& bounds);
@@ -59,9 +58,10 @@ public:
// PlatformWindow:
gfx::Rect GetBounds() override;
void SetBounds(const gfx::Rect& bounds) override;
- void Show() override { }
+ void Show(bool inactive = false) override { }
void Hide() override { }
void Close() override { }
+ bool IsVisible() const { return true; }
void SetTitle(const base::string16&) override { }
void SetCapture() override { }
void ReleaseCapture() override { }
@@ -78,6 +78,11 @@ public:
gfx::Rect GetRestoredBoundsInPixels() const override { return gfx::Rect(); }
void Activate() override { }
void Deactivate() override { }
+ void SetUseNativeFrame(bool use_native_frame) override { }
+ bool ShouldUseNativeFrame() const override { return false; }
+ void SetWindowIcons(const gfx::ImageSkia& window_icon,
+ const gfx::ImageSkia& app_icon) override { }
+ void SizeConstraintsChanged() override { }
// PlatformEventDispatcher:
bool CanDispatchEvent(const PlatformEvent& event) override;
diff --git a/src/core/platform_notification_service_qt.cpp b/src/core/platform_notification_service_qt.cpp
index d8abec17f..5f3017dcf 100644
--- a/src/core/platform_notification_service_qt.cpp
+++ b/src/core/platform_notification_service_qt.cpp
@@ -201,12 +201,11 @@ int64_t PlatformNotificationServiceQt::ReadNextPersistentNotificationId()
void PlatformNotificationServiceQt::ScheduleTrigger(base::Time /*timestamp*/)
{
- Q_UNIMPLEMENTED();
+ QT_NOT_YET_IMPLEMENTED
}
base::Time PlatformNotificationServiceQt::ReadNextTriggerTimestamp()
{
- Q_UNIMPLEMENTED();
return base::Time::Max();
}
diff --git a/src/core/pref_service_adapter.cpp b/src/core/pref_service_adapter.cpp
index ca4be87df..4ded70d07 100644
--- a/src/core/pref_service_adapter.cpp
+++ b/src/core/pref_service_adapter.cpp
@@ -39,12 +39,13 @@
#include "pref_service_adapter.h"
-#include "command_line_pref_store_qt.h"
#include "profile_adapter.h"
#include "type_conversion.h"
#include "web_engine_context.h"
+#include "chrome/browser/prefs/chrome_command_line_pref_store.h"
#include "content/public/browser/browser_thread.h"
+#include "components/language/core/browser/pref_names.h"
#include "components/prefs/pref_member.h"
#include "components/prefs/in_memory_pref_store.h"
#include "components/prefs/json_pref_store.h"
@@ -80,7 +81,7 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
PrefServiceFactory factory;
- factory.set_command_line_prefs(base::MakeRefCounted<CommandLinePrefStoreQt>(
+ factory.set_command_line_prefs(base::MakeRefCounted<ChromeCommandLinePrefStore>(
WebEngineContext::commandLine()));
QString userPrefStorePath = profileAdapter.dataPath();
@@ -92,12 +93,12 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
factory.set_user_prefs(base::MakeRefCounted<JsonPrefStore>(toFilePath(userPrefStorePath)));
}
- PrefRegistrySimple *registry = new PrefRegistrySimple();
- PrefProxyConfigTrackerImpl::RegisterPrefs(registry);
+ auto registry = base::MakeRefCounted<PrefRegistrySimple>();
+ PrefProxyConfigTrackerImpl::RegisterPrefs(registry.get());
#if QT_CONFIG(webengine_spellchecker)
// Initial spellcheck settings
- registry->RegisterStringPref(prefs::kAcceptLanguages, std::string());
+ registry->RegisterStringPref(language::prefs::kAcceptLanguages, std::string());
registry->RegisterListPref(spellcheck::prefs::kSpellCheckDictionaries);
registry->RegisterListPref(spellcheck::prefs::kSpellCheckForcedDictionaries);
registry->RegisterListPref(spellcheck::prefs::kSpellCheckBlacklistedDictionaries);
@@ -122,7 +123,6 @@ void PrefServiceAdapter::setup(const ProfileAdapter &profileAdapter)
registry->RegisterListPref(extensions::pref_names::kNativeMessagingBlacklist);
registry->RegisterListPref(extensions::pref_names::kNativeMessagingWhitelist);
registry->RegisterBooleanPref(extensions::pref_names::kNativeMessagingUserLevelHosts, true);
- registry->RegisterBooleanPref(extensions::pref_names::kInsecureExtensionUpdatesEnabled, false);
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
// Media device salt id key
diff --git a/src/core/printing/print_view_manager_base_qt.cpp b/src/core/printing/print_view_manager_base_qt.cpp
index 4516f10b2..0cc334776 100644
--- a/src/core/printing/print_view_manager_base_qt.cpp
+++ b/src/core/printing/print_view_manager_base_qt.cpp
@@ -50,6 +50,7 @@
#include "base/memory/ref_counted_memory.h"
#include "base/memory/shared_memory.h"
#include "base/message_loop/message_loop.h"
+#include "base/message_loop/message_loop_current.h"
#include "base/run_loop.h"
#include "base/single_thread_task_runner.h"
#include "base/task/post_task.h"
@@ -150,7 +151,8 @@ printing::PrintedDocument *PrintViewManagerBaseQt::GetDocument(int cookie)
// IPC handlers
void PrintViewManagerBaseQt::OnDidPrintDocument(content::RenderFrameHost* /*render_frame_host*/,
- const PrintHostMsg_DidPrintDocument_Params &params)
+ const PrintHostMsg_DidPrintDocument_Params &params,
+ std::unique_ptr<DelayedFrameDispatchHelper> helper)
{
printing::PrintedDocument *document = GetDocument(params.document_cookie);
if (!document)
@@ -172,6 +174,21 @@ void PrintViewManagerBaseQt::OnDidPrintDocument(content::RenderFrameHost* /*rend
PrintDocument(document, data, params.page_size, params.content_area,
params.physical_offsets);
+ if (helper)
+ helper->SendCompleted();
+}
+
+void PrintViewManagerBaseQt::OnGetDefaultPrintSettings(content::RenderFrameHost *render_frame_host,
+ IPC::Message *reply_msg)
+{
+ NOTREACHED() << "should be handled by printing::PrintingMessageFilter";
+}
+
+void PrintViewManagerBaseQt::OnScriptedPrint(content::RenderFrameHost *render_frame_host,
+ const PrintHostMsg_ScriptedPrint_Params &params,
+ IPC::Message *reply_msg)
+{
+ NOTREACHED() << "should be handled by printing::PrintingMessageFilter";
}
void PrintViewManagerBaseQt::OnShowInvalidPrinterSettingsError()
@@ -212,13 +229,6 @@ bool PrintViewManagerBaseQt::OnMessageReceived(const IPC::Message& message,
content::RenderFrameHost* render_frame_host)
{
bool handled = true;
- IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(PrintViewManagerBaseQt, message, render_frame_host)
- IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintDocument, OnDidPrintDocument)
- IPC_MESSAGE_UNHANDLED(handled = false)
- IPC_END_MESSAGE_MAP()
- if (handled)
- return true;
- handled = true;
IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBaseQt, message)
IPC_MESSAGE_HANDLER(PrintHostMsg_ShowInvalidPrinterSettingsError,
OnShowInvalidPrinterSettingsError);
@@ -514,20 +524,21 @@ void PrintViewManagerBaseQt::ReleasePrinterQuery()
printerQuery = m_printerQueriesQueue->PopPrinterQuery(cookie);
if (!printerQuery)
return;
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&printing::PrinterQuery::StopWorker, std::move(printerQuery)));
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&printing::PrinterQuery::StopWorker, std::move(printerQuery)));
}
// Originally from print_preview_message_handler.cc:
-void PrintViewManagerBaseQt::StopWorker(int documentCookie) {
- if (documentCookie <= 0)
- return;
- std::unique_ptr<printing::PrinterQuery> printer_query =
- m_printerQueriesQueue->PopPrinterQuery(documentCookie);
- if (printer_query.get()) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&printing::PrinterQuery::StopWorker, std::move(printer_query)));
- }
+void PrintViewManagerBaseQt::StopWorker(int documentCookie)
+{
+ if (documentCookie <= 0)
+ return;
+ std::unique_ptr<printing::PrinterQuery> printer_query =
+ m_printerQueriesQueue->PopPrinterQuery(documentCookie);
+ if (printer_query.get()) {
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&printing::PrinterQuery::StopWorker, std::move(printer_query)));
+ }
}
void PrintViewManagerBaseQt::SendPrintingEnabled(bool enabled, content::RenderFrameHost* rfh)
diff --git a/src/core/printing/print_view_manager_base_qt.h b/src/core/printing/print_view_manager_base_qt.h
index 31e0a1778..1217e8c11 100644
--- a/src/core/printing/print_view_manager_base_qt.h
+++ b/src/core/printing/print_view_manager_base_qt.h
@@ -98,9 +98,16 @@ protected:
bool OnMessageReceived(const IPC::Message& message,
content::RenderFrameHost* render_frame_host) override;
- // IPC Message handlers.
- void OnDidPrintDocument(content::RenderFrameHost* render_frame_host,
- const PrintHostMsg_DidPrintDocument_Params& params);
+ // printing::PrintManager implementation:
+ void OnDidPrintDocument(content::RenderFrameHost *render_frame_host,
+ const PrintHostMsg_DidPrintDocument_Params &params,
+ std::unique_ptr<DelayedFrameDispatchHelper> helper) override;
+ void OnGetDefaultPrintSettings(content::RenderFrameHost* render_frame_host,
+ IPC::Message* reply_msg) override;
+ void OnScriptedPrint(content::RenderFrameHost* render_frame_host,
+ const PrintHostMsg_ScriptedPrint_Params& params,
+ IPC::Message* reply_msg) override;
+
void OnShowInvalidPrinterSettingsError();
// Processes a NOTIFY_PRINT_JOB_EVENT notification.
diff --git a/src/core/printing/print_view_manager_qt.cpp b/src/core/printing/print_view_manager_qt.cpp
index 7d8039100..ebaad9a80 100644
--- a/src/core/printing/print_view_manager_qt.cpp
+++ b/src/core/printing/print_view_manager_qt.cpp
@@ -66,6 +66,7 @@
#include "printing/metafile_skia.h"
#include "printing/print_job_constants.h"
#include "printing/units.h"
+#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
namespace {
@@ -106,8 +107,8 @@ static void SavePdfFile(scoped_refptr<base::RefCountedBytes> data,
base::File file(path,
base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
bool success = file.IsValid() && metafile.SaveTo(&file);
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(saveCallback, success));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(saveCallback, success));
}
static base::DictionaryValue *createPrintSettings()
@@ -120,10 +121,7 @@ static base::DictionaryValue *createPrintSettings()
printSettings->SetInteger(printing::kPreviewRequestID, internalRequestId);
// The following are standard settings that Chromium expects to be set.
- printSettings->SetBoolean(printing::kSettingPrintToPDF, true);
- printSettings->SetBoolean(printing::kSettingCloudPrintDialog, false);
- printSettings->SetBoolean(printing::kSettingPrintWithPrivet, false);
- printSettings->SetBoolean(printing::kSettingPrintWithExtension, false);
+ printSettings->SetInteger(printing::kSettingPrinterType, printing::kPdfPrinter);
printSettings->SetInteger(printing::kSettingDpiHorizontal, printing::kPointsPerInch);
printSettings->SetInteger(printing::kSettingDpiVertical, printing::kPointsPerInch);
@@ -216,16 +214,16 @@ void PrintViewManagerQt::PrintToPDFFileWithCallback(const QPageLayout &pageLayou
return;
if (m_printSettings || !filePath.length()) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(callback, false));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(callback, false));
return;
}
m_pdfOutputPath = toFilePath(filePath);
m_pdfSaveCallback = callback;
if (!PrintToPDFInternal(pageLayout, printInColor)) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(callback, false));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(callback, false));
resetPdfState();
}
}
@@ -240,15 +238,15 @@ void PrintViewManagerQt::PrintToPDFWithCallback(const QPageLayout &pageLayout,
// If there already is a pending print in progress, don't try starting another one.
if (m_printSettings) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(callback, QSharedPointer<QByteArray>()));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(callback, QSharedPointer<QByteArray>()));
return;
}
m_pdfPrintCallback = callback;
if (!PrintToPDFInternal(pageLayout, printInColor, useCustomMargins)) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(callback, QSharedPointer<QByteArray>()));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(callback, QSharedPointer<QByteArray>()));
resetPdfState();
}
@@ -272,15 +270,9 @@ bool PrintViewManagerQt::PrintToPDFInternal(const QPageLayout &pageLayout,
return false;
content::RenderFrameHost* rfh = web_contents()->GetMainFrame();
- auto message = std::make_unique<PrintMsg_InitiatePrintPreview>(
- rfh->GetRoutingID(), false);
+ GetPrintRenderFrame(rfh)->InitiatePrintPreview(nullptr, false);
DCHECK(!m_printPreviewRfh);
-
- if (!rfh->Send(message.release())) {
- return false;
- }
-
m_printPreviewRfh = rfh;
return true;
}
@@ -324,6 +316,24 @@ void PrintViewManagerQt::RenderFrameDeleted(content::RenderFrameHost *render_fra
if (render_frame_host == m_printPreviewRfh)
PrintPreviewDone();
PrintViewManagerBaseQt::RenderFrameDeleted(render_frame_host);
+ m_printRenderFrames.erase(render_frame_host);
+}
+
+const mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> &PrintViewManagerQt::GetPrintRenderFrame(content::RenderFrameHost *rfh)
+{
+ auto it = m_printRenderFrames.find(rfh);
+ if (it == m_printRenderFrames.end()) {
+ mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> remote;
+ rfh->GetRemoteAssociatedInterfaces()->GetInterface(&remote);
+ it = m_printRenderFrames.insert(std::make_pair(rfh, std::move(remote))).first;
+ } else if (it->second.is_bound() && !it->second.is_connected()) {
+ // When print preview is closed, the remote is disconnected from the
+ // receiver. Reset and bind the remote before using it again.
+ it->second.reset();
+ rfh->GetRemoteAssociatedInterfaces()->GetInterface(&it->second);
+ }
+
+ return it->second;
}
void PrintViewManagerQt::resetPdfState()
@@ -359,12 +369,12 @@ void PrintViewManagerQt::OnMetafileReadyForPrinting(content::RenderFrameHost* rf
if (!pdf_print_callback.is_null()) {
QSharedPointer<QByteArray> data_array = GetStdVectorFromHandle(params.content.metafile_data_region);
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(pdf_print_callback, data_array));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(pdf_print_callback, data_array));
} else {
scoped_refptr<base::RefCountedBytes> data_bytes = GetBytesFromHandle(params.content.metafile_data_region);
- base::PostTaskWithTraits(FROM_HERE, {base::MayBlock()},
- base::BindOnce(&SavePdfFile, data_bytes, pdfOutputPath, pdf_save_callback));
+ base::PostTask(FROM_HERE, {base::ThreadPool(), base::MayBlock()},
+ base::BindOnce(&SavePdfFile, data_bytes, pdfOutputPath, pdf_save_callback));
}
}
@@ -382,8 +392,8 @@ void PrintViewManagerQt::DidStartLoading()
void PrintViewManagerQt::NavigationStopped()
{
if (!m_pdfPrintCallback.is_null()) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>()));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>()));
}
resetPdfState();
PrintViewManagerBaseQt::NavigationStopped();
@@ -393,8 +403,8 @@ void PrintViewManagerQt::RenderProcessGone(base::TerminationStatus status)
{
PrintViewManagerBaseQt::RenderProcessGone(status);
if (!m_pdfPrintCallback.is_null()) {
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>()));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(m_pdfPrintCallback, QSharedPointer<QByteArray>()));
}
resetPdfState();
}
@@ -419,7 +429,7 @@ void PrintViewManagerQt::OnSetupScriptedPrintPreview(content::RenderFrameHost* r
return;
// close preview
- rfh->Send(new PrintMsg_ClosePrintPreviewDialog(rfh->GetRoutingID()));
+ GetPrintRenderFrame(rfh)->OnPrintPreviewDialogClosed();
client->printRequested();
}
@@ -431,8 +441,7 @@ void PrintViewManagerQt::OnShowScriptedPrintPreview(content::RenderFrameHost* rf
}
void PrintViewManagerQt::PrintPreviewDone() {
- m_printPreviewRfh->Send(new PrintMsg_ClosePrintPreviewDialog(
- m_printPreviewRfh->GetRoutingID()));
+ GetPrintRenderFrame(m_printPreviewRfh)->OnPrintPreviewDialogClosed();
m_printPreviewRfh = nullptr;
}
diff --git a/src/core/printing/print_view_manager_qt.h b/src/core/printing/print_view_manager_qt.h
index 14f2688dd..06c2f47ea 100644
--- a/src/core/printing/print_view_manager_qt.h
+++ b/src/core/printing/print_view_manager_qt.h
@@ -47,14 +47,17 @@
#include "print_view_manager_base_qt.h"
#include "qtwebenginecoreglobal_p.h"
+
#include "base/memory/ref_counted.h"
#include "base/strings/string16.h"
#include "components/prefs/pref_member.h"
#include "components/printing/browser/print_manager.h"
+#include "components/printing/common/print.mojom.h"
#include "components/printing/common/print_messages.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/web_contents_user_data.h"
+#include "mojo/public/cpp/bindings/associated_remote.h"
#include <QSharedPointer>
@@ -132,6 +135,11 @@ protected:
private:
void resetPdfState();
+
+ // Helper method to fetch the PrintRenderFrame associated remote interface
+ // pointer.
+ const mojo::AssociatedRemote<printing::mojom::PrintRenderFrame> &GetPrintRenderFrame(content::RenderFrameHost *rfh);
+
// content::WebContentsObserver implementation.
void DidStartLoading() override;
void PrintPreviewDone();
@@ -143,6 +151,9 @@ private:
PrintToPDFCallback m_pdfPrintCallback;
PrintToPDFFileCallback m_pdfSaveCallback;
std::unique_ptr<base::DictionaryValue> m_printSettings;
+
+ std::map<content::RenderFrameHost*,mojo::AssociatedRemote<printing::mojom::PrintRenderFrame>> m_printRenderFrames;
+
friend class content::WebContentsUserData<PrintViewManagerQt>;
DISALLOW_COPY_AND_ASSIGN(PrintViewManagerQt);
struct FrameDispatchHelper;
diff --git a/src/core/profile_adapter.cpp b/src/core/profile_adapter.cpp
index bccdf1ada..e9e2a2c5d 100644
--- a/src/core/profile_adapter.cpp
+++ b/src/core/profile_adapter.cpp
@@ -43,13 +43,17 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browsing_data_remover.h"
#include "content/public/browser/download_manager.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
+#include "content/public/browser/storage_partition.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
+#include "url/url_util.h"
#include "api/qwebengineurlscheme.h"
#include "content_browser_client_qt.h"
#include "download_manager_delegate_qt.h"
-#include "net/url_request_context_getter_qt.h"
#include "permission_manager_qt.h"
#include "profile_adapter_client.h"
+#include "profile_io_data_qt.h"
#include "profile_qt.h"
#include "renderer_host/user_resource_controller_host.h"
#include "type_conversion.h"
@@ -104,6 +108,17 @@ ProfileAdapter::ProfileAdapter(const QString &storageName):
if (!storageName.isEmpty())
extensions::ExtensionSystem::Get(m_profile.data())->InitForRegularProfile(true);
#endif
+
+ // Allow XMLHttpRequests from qrc to file.
+ // ### consider removing for Qt6
+ url::Origin qrc = url::Origin::Create(GURL("qrc://"));
+ auto pattern = network::mojom::CorsOriginPattern::New("file", "", 0,
+ network::mojom::CorsDomainMatchMode::kAllowSubdomains,
+ network::mojom::CorsPortMatchMode::kAllowAnyPort,
+ network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
+ std::vector<network::mojom::CorsOriginPatternPtr> list;
+ list.push_back(std::move(pattern));
+ m_profile->GetSharedCorsOriginAccessList()->SetForOrigin(qrc, std::move(list), {}, base::BindOnce([]{}));
}
ProfileAdapter::~ProfileAdapter()
@@ -129,8 +144,7 @@ void ProfileAdapter::setStorageName(const QString &storageName)
m_name = storageName;
if (!m_offTheRecord) {
m_profile->setupPrefService();
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateStorageSettings();
+ m_profile->m_profileIOData->resetNetworkContext();
if (m_visitedLinksManager)
resetVisitedLinksManager();
}
@@ -142,8 +156,7 @@ void ProfileAdapter::setOffTheRecord(bool offTheRecord)
return;
m_offTheRecord = offTheRecord;
m_profile->setupPrefService();
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateStorageSettings();
+ m_profile->m_profileIOData->resetNetworkContext();
if (m_visitedLinksManager)
resetVisitedLinksManager();
}
@@ -193,8 +206,7 @@ void ProfileAdapter::setRequestInterceptor(QWebEngineUrlRequestInterceptor *inte
Q_ASSERT(!m_profile->m_profileIOData->requestInterceptor());
});
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateRequestInterceptor();
+ m_profile->m_profileIOData->updateRequestInterceptor();
}
void ProfileAdapter::addClient(ProfileAdapterClient *adapterClient)
@@ -210,16 +222,14 @@ void ProfileAdapter::removeClient(ProfileAdapterClient *adapterClient)
void ProfileAdapter::addPageRequestInterceptor()
{
++m_pageRequestInterceptors;
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateRequestInterceptor();
+ m_profile->m_profileIOData->updateRequestInterceptor();
}
void ProfileAdapter::removePageRequestInterceptor()
{
Q_ASSERT(m_pageRequestInterceptors > 0);
--m_pageRequestInterceptors;
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateRequestInterceptor();
+ m_profile->m_profileIOData->updateRequestInterceptor();
}
@@ -277,8 +287,7 @@ void ProfileAdapter::setDataPath(const QString &path)
m_dataPath = path;
if (!m_offTheRecord) {
m_profile->setupPrefService();
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateStorageSettings();
+ m_profile->m_profileIOData->resetNetworkContext();
if (m_visitedLinksManager)
resetVisitedLinksManager();
}
@@ -305,8 +314,8 @@ void ProfileAdapter::setCachePath(const QString &path)
if (m_cachePath == path)
return;
m_cachePath = path;
- if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateHttpCache();
+ if (!m_offTheRecord)
+ m_profile->m_profileIOData->resetNetworkContext();
}
QString ProfileAdapter::cookiesPath() const
@@ -343,17 +352,21 @@ QString ProfileAdapter::httpUserAgent() const
void ProfileAdapter::setHttpUserAgent(const QString &userAgent)
{
- if (m_httpUserAgent == userAgent)
+ const QString httpUserAgent = userAgent.simplified();
+ if (m_httpUserAgent == httpUserAgent)
return;
- m_httpUserAgent = userAgent.simplified();
+ m_httpUserAgent = httpUserAgent;
+ const std::string stdUserAgent = httpUserAgent.toStdString();
std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
for (content::WebContentsImpl *web_contents : list)
if (web_contents->GetBrowserContext() == m_profile.data())
- web_contents->SetUserAgentOverride(m_httpUserAgent.toStdString(), true);
+ web_contents->SetUserAgentOverride(stdUserAgent, true);
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateUserAgent();
+ content::BrowserContext::ForEachStoragePartition(
+ m_profile.get(), base::BindRepeating([](const std::string &user_agent, content::StoragePartition *storage_partition) {
+ storage_partition->GetNetworkContext()->SetUserAgent(user_agent);
+ }, stdUserAgent));
}
ProfileAdapter::HttpCacheType ProfileAdapter::httpCacheType() const
@@ -371,8 +384,11 @@ void ProfileAdapter::setHttpCacheType(ProfileAdapter::HttpCacheType newhttpCache
m_httpCacheType = newhttpCacheType;
if (oldCacheType == httpCacheType())
return;
- if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateHttpCache();
+ if (!m_offTheRecord) {
+ m_profile->m_profileIOData->resetNetworkContext();
+ if (m_httpCacheType == NoCache)
+ clearHttpCache();
+ }
}
ProfileAdapter::PersistentCookiesPolicy ProfileAdapter::persistentCookiesPolicy() const
@@ -388,8 +404,8 @@ void ProfileAdapter::setPersistentCookiesPolicy(ProfileAdapter::PersistentCookie
m_persistentCookiesPolicy = newPersistentCookiesPolicy;
if (oldPolicy == persistentCookiesPolicy())
return;
- if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateCookieStore();
+ if (!m_offTheRecord)
+ m_profile->m_profileIOData->resetNetworkContext();
}
ProfileAdapter::VisitedLinksPolicy ProfileAdapter::visitedLinksPolicy() const
@@ -443,8 +459,8 @@ void ProfileAdapter::setHttpCacheMaxSize(int maxSize)
if (m_httpCacheMaxSize == maxSize)
return;
m_httpCacheMaxSize = maxSize;
- if (!m_offTheRecord && m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateHttpCache();
+ if (!m_offTheRecord)
+ m_profile->m_profileIOData->resetNetworkContext();
}
enum class SchemeType { Protected, Overridable, Custom, Unknown };
@@ -489,8 +505,10 @@ const QList<QByteArray> ProfileAdapter::customUrlSchemes() const
void ProfileAdapter::updateCustomUrlSchemeHandlers()
{
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateJobFactory();
+ content::BrowserContext::ForEachStoragePartition(
+ m_profile.get(), base::BindRepeating([](content::StoragePartition *storage_partition) {
+ storage_partition->ResetURLLoaderFactories();
+ }));
}
void ProfileAdapter::removeUrlSchemeHandler(QWebEngineUrlSchemeHandler *handler)
@@ -551,9 +569,11 @@ void ProfileAdapter::installUrlSchemeHandler(const QByteArray &scheme, QWebEngin
void ProfileAdapter::removeAllUrlSchemeHandlers()
{
- m_customUrlSchemeHandlers.clear();
- m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler);
- updateCustomUrlSchemeHandlers();
+ if (m_customUrlSchemeHandlers.size() > 1) {
+ m_customUrlSchemeHandlers.clear();
+ m_customUrlSchemeHandlers.insert(QByteArrayLiteral("qrc"), &m_qrcHandler);
+ updateCustomUrlSchemeHandlers();
+ }
}
UserResourceControllerHost *ProfileAdapter::userResourceController()
@@ -596,17 +616,21 @@ void ProfileAdapter::setHttpAcceptLanguage(const QString &httpAcceptLanguage)
return;
m_httpAcceptLanguage = httpAcceptLanguage;
+ std::string http_accept_language = httpAcceptLanguageWithoutQualities().toStdString();
+
std::vector<content::WebContentsImpl *> list = content::WebContentsImpl::GetAllWebContents();
for (content::WebContentsImpl *web_contents : list) {
if (web_contents->GetBrowserContext() == m_profile.data()) {
blink::mojom::RendererPreferences *rendererPrefs = web_contents->GetMutableRendererPrefs();
- rendererPrefs->accept_languages = httpAcceptLanguageWithoutQualities().toStdString();
- web_contents->GetRenderViewHost()->SyncRendererPrefs();
+ rendererPrefs->accept_languages = http_accept_language;
+ web_contents->SyncRendererPrefs();
}
}
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateUserAgent();
+ content::BrowserContext::ForEachStoragePartition(
+ m_profile.get(), base::BindRepeating([](std::string accept_language, content::StoragePartition *storage_partition) {
+ storage_partition->GetNetworkContext()->SetAcceptLanguage(accept_language);
+ }, http_accept_language));
}
void ProfileAdapter::clearHttpCache()
@@ -675,6 +699,7 @@ void ProfileAdapter::setUseForGlobalCertificateVerification(bool enable)
if (enable) {
if (profileForglobalCertificateVerification) {
profileForglobalCertificateVerification->m_usedForGlobalCertificateVerification = false;
+ profileForglobalCertificateVerification->m_profile->m_profileIOData->resetNetworkContext();
for (auto *client : qAsConst(profileForglobalCertificateVerification->m_clients))
client->useForGlobalCertificateVerificationChanged();
}
@@ -685,8 +710,7 @@ void ProfileAdapter::setUseForGlobalCertificateVerification(bool enable)
profileForglobalCertificateVerification = nullptr;
}
- if (m_profile->m_urlRequestContextGetter.get())
- m_profile->m_profileIOData->updateUsedForGlobalCertificateVerification();
+ m_profile->m_profileIOData->resetNetworkContext();
}
bool ProfileAdapter::isUsedForGlobalCertificateVerification() const
@@ -700,7 +724,7 @@ QString ProfileAdapter::determineDownloadPath(const QString &downloadDirectory,
QString suggestedFilePath = suggestedFile.absoluteFilePath();
base::FilePath tmpFilePath(toFilePath(suggestedFilePath).NormalizePathSeparatorsTo('/'));
- int uniquifier = base::GetUniquePathNumber(tmpFilePath, base::FilePath::StringType());
+ int uniquifier = base::GetUniquePathNumber(tmpFilePath);
if (uniquifier > 0)
suggestedFilePath = toQt(tmpFilePath.InsertBeforeExtensionASCII(base::StringPrintf(" (%d)", uniquifier)).AsUTF8Unsafe());
else if (uniquifier == -1) {
diff --git a/src/core/profile_io_data_qt.cpp b/src/core/profile_io_data_qt.cpp
index 68be09ad2..91af8d544 100644
--- a/src/core/profile_io_data_qt.cpp
+++ b/src/core/profile_io_data_qt.cpp
@@ -40,131 +40,30 @@
#include "profile_io_data_qt.h"
#include "base/task/post_task.h"
-#include "components/certificate_transparency/ct_known_logs.h"
-#include "components/network_session_configurator/common/network_features.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/cookie_store_factory.h"
+#include "content/public/browser/shared_cors_origin_access_list.h"
#include "content/public/common/content_features.h"
-#include "chrome/browser/custom_handlers/protocol_handler_registry_factory.h"
-#include "chrome/browser/net/chrome_mojo_proxy_resolver_factory.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
-#include "net/cert/cert_verifier.h"
-#include "net/cert/ct_log_verifier.h"
-#include "net/cert/ct_policy_enforcer.h"
-#include "net/cert/multi_log_ct_verifier.h"
-#include "net/cert_net/cert_net_fetcher_impl.h"
-#include "net/ftp/ftp_auth_cache.h"
-#include "net/dns/host_resolver_manager.h"
-#include "net/http/http_auth_handler_factory.h"
-#include "net/http/http_auth_scheme.h"
-#include "net/http/http_auth_preferences.h"
-#include "net/http/http_cache.h"
-#include "net/http/http_server_properties_impl.h"
-#include "net/http/http_network_session.h"
-#include "net/http/transport_security_persister.h"
-#include "net/proxy_resolution/dhcp_pac_file_fetcher_factory.h"
-#include "net/proxy_resolution/pac_file_fetcher_impl.h"
-#include "net/proxy_resolution/proxy_config_service.h"
-#include "net/proxy_resolution/proxy_resolution_service.h"
#include "net/ssl/ssl_config_service_defaults.h"
-#include "net/url_request/data_protocol_handler.h"
-#include "net/url_request/file_protocol_handler.h"
-#include "net/url_request/ftp_protocol_handler.h"
-#include "net/url_request/static_http_user_agent_settings.h"
-#include "net/url_request/url_request_context_storage.h"
-#include "net/url_request/url_request_job_factory_impl.h"
-#include "net/url_request/url_request_intercepting_job_factory.h"
-#include "services/file/user_id_map.h"
-#include "services/network/proxy_service_mojo.h"
-#include "services/network/restricted_cookie_manager.h"
+#include "services/network/public/cpp/cors/origin_access_list.h"
#include "net/client_cert_override.h"
#include "net/client_cert_store_data.h"
#include "net/cookie_monster_delegate_qt.h"
-#include "net/custom_protocol_handler.h"
-#include "net/network_delegate_qt.h"
-#include "net/proxy_config_service_qt.h"
-#include "net/restricted_cookie_manager_qt.h"
-#include "net/url_request_context_getter_qt.h"
+#include "net/system_network_context_manager.h"
#include "profile_qt.h"
#include "resource_context_qt.h"
#include "type_conversion.h"
-#if defined(USE_NSS_CERTS)
-#include "net/cert_net/nss_ocsp.h"
-#endif
-
-#if defined(OS_LINUX) || defined(OS_MACOSX)
-#include "net/cert/cert_net_fetcher.h"
-#include "net/cert_net/cert_net_fetcher_impl.h"
-#endif
+#include <QDebug>
+#include <QVariant>
#include <mutex>
namespace QtWebEngineCore {
-static scoped_refptr<net::CertNetFetcherImpl> s_certNetFetcher;
-
-static bool doNetworkSessionParamsMatch(const net::HttpNetworkSession::Params &first,
- const net::HttpNetworkSession::Params &second)
-{
- if (first.ignore_certificate_errors != second.ignore_certificate_errors)
- return false;
- return true;
-}
-
-static bool doNetworkSessionContextMatch(const net::HttpNetworkSession::Context &first,
- const net::HttpNetworkSession::Context &second)
-{
- if (first.transport_security_state != second.transport_security_state)
- return false;
- if (first.cert_verifier != second.cert_verifier)
- return false;
- if (first.proxy_resolution_service != second.proxy_resolution_service)
- return false;
- if (first.ssl_config_service != second.ssl_config_service)
- return false;
- if (first.http_auth_handler_factory != second.http_auth_handler_factory)
- return false;
- if (first.http_user_agent_settings != second.http_user_agent_settings)
- return false;
- if (first.http_server_properties != second.http_server_properties)
- return false;
- if (first.host_resolver != second.host_resolver)
- return false;
- if (first.cert_transparency_verifier != second.cert_transparency_verifier)
- return false;
- if (first.ct_policy_enforcer != second.ct_policy_enforcer)
- return false;
- return true;
-}
-
-static net::HttpNetworkSession::Context generateNetworkSessionContext(net::URLRequestContext *urlRequestContext)
-{
- net::HttpNetworkSession::Context network_session_context;
- network_session_context.transport_security_state = urlRequestContext->transport_security_state();
- network_session_context.cert_verifier = urlRequestContext->cert_verifier();
- network_session_context.proxy_resolution_service = urlRequestContext->proxy_resolution_service();
- network_session_context.ssl_config_service = urlRequestContext->ssl_config_service();
- network_session_context.http_auth_handler_factory = urlRequestContext->http_auth_handler_factory();
- network_session_context.http_user_agent_settings = urlRequestContext->http_user_agent_settings();
- network_session_context.http_server_properties = urlRequestContext->http_server_properties();
- network_session_context.host_resolver = urlRequestContext->host_resolver();
- network_session_context.cert_transparency_verifier = urlRequestContext->cert_transparency_verifier();
- network_session_context.ct_policy_enforcer = urlRequestContext->ct_policy_enforcer();
- return network_session_context;
-}
-
-static net::HttpNetworkSession::Params generateNetworkSessionParams(bool ignoreCertificateErrors)
-{
- net::HttpNetworkSession::Params network_session_params;
- network_session_params.ignore_certificate_errors = ignoreCertificateErrors;
- return network_session_params;
-}
-
ProfileIODataQt::ProfileIODataQt(ProfileQt *profile)
: m_profile(profile),
#if QT_CONFIG(ssl)
@@ -182,28 +81,7 @@ ProfileIODataQt::~ProfileIODataQt()
if (content::BrowserThread::IsThreadInitialized(content::BrowserThread::IO))
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- if (m_useForGlobalCertificateVerification) {
-#if defined(USE_NSS_CERTS)
- net::SetURLRequestContextForNSSHttpIO(nullptr);
-#endif
- if (s_certNetFetcher) {
- s_certNetFetcher->Shutdown();
- s_certNetFetcher.reset();
- }
- }
-
- if (m_urlRequestContext) {
- if (m_urlRequestContext->proxy_resolution_service())
- m_urlRequestContext->proxy_resolution_service()->OnShutdown();
- m_restrictedCookieManagerBindings.CloseAllBindings();
- cancelAllUrlRequests();
- }
-
m_resourceContext.reset();
- if (m_cookieDelegate)
- m_cookieDelegate->setCookieMonster(0); // this will let CookieMonsterDelegateQt be deleted
- m_networkDelegate.reset();
- delete m_proxyConfigService.fetchAndStoreAcquire(0);
}
QPointer<ProfileAdapter> ProfileIODataQt::profileAdapter()
@@ -218,6 +96,9 @@ void ProfileIODataQt::shutdownOnUIThread()
delete m_clientCertificateStoreData;
m_clientCertificateStoreData = nullptr;
#endif
+ if (m_cookieDelegate)
+ m_cookieDelegate->unsetMojoCookieManager();
+ m_proxyConfigMonitor.reset();
bool posted = content::BrowserThread::DeleteSoon(content::BrowserThread::IO, FROM_HERE, this);
if (!posted) {
qWarning() << "Could not delete ProfileIODataQt on io thread !";
@@ -230,7 +111,7 @@ net::URLRequestContext *ProfileIODataQt::urlRequestContext()
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (!m_initialized)
initializeOnIOThread();
- return m_urlRequestContext.get();
+ return nullptr;
}
content::ResourceContext *ProfileIODataQt::resourceContext()
@@ -248,22 +129,22 @@ extensions::ExtensionSystemQt* ProfileIODataQt::GetExtensionSystem()
base::WeakPtr<ProfileIODataQt> ProfileIODataQt::getWeakPtrOnUIThread()
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+ DCHECK(m_initialized);
return m_weakPtr;
}
+base::WeakPtr<ProfileIODataQt> ProfileIODataQt::getWeakPtrOnIOThread()
+{
+ DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+ return m_weakPtrFactory.GetWeakPtr();
+}
+
void ProfileIODataQt::initializeOnIOThread()
{
- m_networkDelegate.reset(new NetworkDelegateQt(this));
- m_hostResolver = net::HostResolver::CreateStandaloneResolver(nullptr);
- m_urlRequestContext.reset(new net::URLRequestContext());
- m_urlRequestContext->set_network_delegate(m_networkDelegate.get());
- m_urlRequestContext->set_enable_brotli(true);
- m_urlRequestContext->set_host_resolver(m_hostResolver.get());
// this binds factory to io thread
m_weakPtr = m_weakPtrFactory.GetWeakPtr();
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
generateAllStorage();
- generateJobFactory();
setGlobalCertificateVerification();
m_initialized = true;
}
@@ -273,300 +154,21 @@ void ProfileIODataQt::initializeOnUIThread()
m_profileAdapter = m_profile->profileAdapter();
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
m_resourceContext.reset(new ResourceContextQt(this));
- ProtocolHandlerRegistry* protocolHandlerRegistry =
- ProtocolHandlerRegistryFactory::GetForBrowserContext(m_profile);
- DCHECK(protocolHandlerRegistry);
- m_protocolHandlerRegistryIOThreadDelegate = protocolHandlerRegistry->io_thread_delegate();
m_cookieDelegate = new CookieMonsterDelegateQt();
m_cookieDelegate->setClient(m_profile->profileAdapter()->cookieStore());
- createProxyConfig();
-}
-
-void ProfileIODataQt::cancelAllUrlRequests()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
-
- const std::set<const net::URLRequest*> *url_requests = m_urlRequestContext->url_requests();
- std::set<const net::URLRequest*>::const_iterator it = url_requests->begin();
- std::set<const net::URLRequest*>::const_iterator end = url_requests->end();
- for ( ; it != end; ++it) {
- net::URLRequest* request = const_cast<net::URLRequest*>(*it);
- if (request)
- request->Cancel();
- }
+ m_proxyConfigMonitor.reset(new ProxyConfigMonitor(m_profile->GetPrefs()));
}
void ProfileIODataQt::generateAllStorage()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
- generateStorage();
- generateCookieStore();
- generateUserAgent();
- generateHttpCache();
m_updateAllStorage = false;
}
-void ProfileIODataQt::generateStorage()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
-// Q_ASSERT(!m_mutex.tryLock()); // assert locked
-
- // We must stop all requests before deleting their backends.
- if (m_storage) {
- m_urlRequestContext->proxy_resolution_service()->OnShutdown();
- m_restrictedCookieManagerBindings.CloseAllBindings();
- m_cookieDelegate->setCookieMonster(nullptr);
- m_storage->set_cookie_store(nullptr);
- cancelAllUrlRequests();
- // we need to get rid of dangling pointer due to coming storage deletion
- m_urlRequestContext->set_http_transaction_factory(nullptr);
- m_httpNetworkSession.reset();
- m_transportSecurityPersister.reset();
- }
-
- m_storage.reset(new net::URLRequestContextStorage(m_urlRequestContext.get()));
-
- net::ProxyConfigService *proxyConfigService = m_proxyConfigService.fetchAndStoreAcquire(0);
- Q_ASSERT(proxyConfigService);
-
- std::unique_ptr<net::CertVerifier> cert_verifier = net::CertVerifier::CreateDefault(s_certNetFetcher);
- net::CertVerifier::Config config;
- // Enable revocation checking:
- config.enable_rev_checking = true;
- // Mirroring Android WebView (we have no beef with Symantec, and our users might use them):
- config.disable_symantec_enforcement = true;
- cert_verifier->SetConfig(config);
-
- m_storage->set_cert_verifier(std::move(cert_verifier));
- std::unique_ptr<net::MultiLogCTVerifier> ct_verifier(new net::MultiLogCTVerifier());
- std::vector<scoped_refptr<const net::CTLogVerifier>> ct_logs;
- for (const auto &ct_log : certificate_transparency::GetKnownLogs()) {
- scoped_refptr<const net::CTLogVerifier> log_verifier =
- net::CTLogVerifier::Create(std::string(ct_log.log_key, ct_log.log_key_length),
- ct_log.log_name);
- if (!log_verifier)
- continue;
- ct_logs.push_back(std::move(log_verifier));
- }
- ct_verifier->AddLogs(ct_logs);
- m_storage->set_cert_transparency_verifier(std::move(ct_verifier));
- m_storage->set_ct_policy_enforcer(base::WrapUnique(new net::DefaultCTPolicyEnforcer()));
- m_storage->set_ssl_config_service(std::make_unique<net::SSLConfigServiceDefaults>());
- if (!m_httpAuthPreferences) {
- m_httpAuthPreferences.reset(new net::HttpAuthPreferences());
- std::string serverWhitelist = base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(switches::kAuthServerWhitelist);
- m_httpAuthPreferences->SetServerWhitelist(serverWhitelist);
- }
- m_storage->set_http_auth_handler_factory(net::HttpAuthHandlerFactory::CreateDefault(
- m_httpAuthPreferences.get()));
- m_storage->set_transport_security_state(std::make_unique<net::TransportSecurityState>());
-
- if (!m_dataPath.isEmpty()) {
- scoped_refptr<base::SequencedTaskRunner> background_task_runner(
- base::CreateSequencedTaskRunnerWithTraits(
- {base::MayBlock(),
- base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::BLOCK_SHUTDOWN}));
- m_transportSecurityPersister =
- std::make_unique<net::TransportSecurityPersister>(
- m_urlRequestContext->transport_security_state(),
- toFilePath(m_dataPath),
- background_task_runner);
- };
-
- m_storage->set_http_server_properties(std::unique_ptr<net::HttpServerProperties>(
- new net::HttpServerPropertiesImpl));
-
- // The System Proxy Resolver has issues on Windows with unconfigured network cards,
- // which is why we want to use the v8 one
- if (!m_dhcpPacFileFetcherFactory)
- m_dhcpPacFileFetcherFactory.reset(new net::DhcpPacFileFetcherFactory);
-
- proxy_resolver::mojom::ProxyResolverFactoryPtr proxyResolver(std::move(m_proxyResolverFactoryInterface));
- m_storage->set_proxy_resolution_service(network::CreateProxyResolutionServiceUsingMojoFactory(
- std::move(proxyResolver),
- std::unique_ptr<net::ProxyConfigService>(proxyConfigService),
- net::PacFileFetcherImpl::CreateWithFileUrlSupport(m_urlRequestContext.get()),
- m_dhcpPacFileFetcherFactory->Create(m_urlRequestContext.get()),
- m_urlRequestContext->host_resolver(),
- nullptr /* NetLog */,
- m_urlRequestContext->network_delegate()));
-
- m_storage->set_ftp_auth_cache(std::make_unique<net::FtpAuthCache>());
-}
-
-
-void ProfileIODataQt::generateCookieStore()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
-
- const std::lock_guard<QRecursiveMutex> lock(m_mutex);
-
- // FIXME: Add code to remove the old channel-id database.
-
- std::unique_ptr<net::CookieStore> cookieStore;
- switch (m_persistentCookiesPolicy) {
- case ProfileAdapter::NoPersistentCookies:
- cookieStore = content::CreateCookieStore(
- content::CookieStoreConfig(
- base::FilePath(),
- false,
- false,
- nullptr),
- nullptr);
- break;
- case ProfileAdapter::AllowPersistentCookies:
- cookieStore = content::CreateCookieStore(
- content::CookieStoreConfig(
- toFilePath(m_cookiesPath),
- false,
- true,
- nullptr),
- nullptr);
- break;
- case ProfileAdapter::ForcePersistentCookies:
- cookieStore = content::CreateCookieStore(
- content::CookieStoreConfig(
- toFilePath(m_cookiesPath),
- true,
- true,
- nullptr),
- nullptr);
- break;
- }
-
- net::CookieMonster * const cookieMonster = static_cast<net::CookieMonster*>(cookieStore.get());
- m_cookieDelegate->setCookieMonster(cookieMonster);
- m_storage->set_cookie_store(std::move(cookieStore));
-
- const std::vector<std::string> cookieableSchemes(kCookieableSchemes,
- kCookieableSchemes + base::size(kCookieableSchemes));
- cookieMonster->SetCookieableSchemes(cookieableSchemes, base::DoNothing());
-}
-
-void ProfileIODataQt::generateUserAgent()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
- Q_ASSERT(m_storage);
-
- const std::lock_guard<QRecursiveMutex> lock(m_mutex);
- m_storage->set_http_user_agent_settings(std::unique_ptr<net::HttpUserAgentSettings>(
- new net::StaticHttpUserAgentSettings(m_httpAcceptLanguage.toStdString(),
- m_httpUserAgent.toStdString())));
-}
-
-void ProfileIODataQt::generateHttpCache()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
- Q_ASSERT(m_storage);
-
- const std::lock_guard<QRecursiveMutex> lock(m_mutex);
-
- net::HttpCache::DefaultBackend* main_backend = 0;
- switch (m_httpCacheType) {
- case ProfileAdapter::MemoryHttpCache:
- main_backend =
- new net::HttpCache::DefaultBackend(
- net::MEMORY_CACHE,
- net::CACHE_BACKEND_DEFAULT,
- base::FilePath(),
- m_httpCacheMaxSize
- );
- break;
- case ProfileAdapter::DiskHttpCache:
- main_backend =
- new net::HttpCache::DefaultBackend(
- net::DISK_CACHE,
- net::CACHE_BACKEND_DEFAULT,
- toFilePath(m_httpCachePath),
- m_httpCacheMaxSize
- );
- break;
- case ProfileAdapter::NoCache:
- // It's safe to not create BackendFactory.
- break;
- }
-
- net::HttpCache *cache = 0;
- net::HttpNetworkSession::Context network_session_context =
- generateNetworkSessionContext(m_urlRequestContext.get());
- net::HttpNetworkSession::Params network_session_params =
- generateNetworkSessionParams(m_ignoreCertificateErrors);
-
- if (!m_httpNetworkSession
- || !doNetworkSessionParamsMatch(network_session_params, m_httpNetworkSession->params())
- || !doNetworkSessionContextMatch(network_session_context, m_httpNetworkSession->context())) {
- m_httpNetworkSession.reset(new net::HttpNetworkSession(network_session_params,
- network_session_context));
- }
-
- cache = new net::HttpCache(m_httpNetworkSession.get(),
- std::unique_ptr<net::HttpCache::DefaultBackend>(main_backend), false);
-
- m_storage->set_http_transaction_factory(std::unique_ptr<net::HttpCache>(cache));
-}
-
-void ProfileIODataQt::generateJobFactory()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
- Q_ASSERT(!m_jobFactory);
-
- const std::lock_guard<QRecursiveMutex> lock(m_mutex);
- m_updateJobFactory = false;
-
- std::unique_ptr<net::URLRequestJobFactoryImpl> jobFactory(new net::URLRequestJobFactoryImpl());
- for (auto &it : m_protocolHandlers)
- jobFactory->SetProtocolHandler(it.first, base::WrapUnique(it.second.release()));
- m_protocolHandlers.clear();
-
- jobFactory->SetProtocolHandler(url::kDataScheme,
- std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>(
- new net::DataProtocolHandler()));
- scoped_refptr<base::TaskRunner> taskRunner(base::CreateTaskRunnerWithTraits({base::MayBlock(),
- base::TaskPriority::BEST_EFFORT,
- base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}));
- jobFactory->SetProtocolHandler(url::kFileScheme,
- std::make_unique<net::FileProtocolHandler>(taskRunner));
- jobFactory->SetProtocolHandler(url::kFtpScheme,
- net::FtpProtocolHandler::Create(m_urlRequestContext->host_resolver(), m_urlRequestContext->ftp_auth_cache()));
-
- m_installedCustomSchemes = m_customUrlSchemes;
- for (const QByteArray &scheme : qAsConst(m_installedCustomSchemes)) {
- jobFactory->SetProtocolHandler(scheme.toStdString(),
- std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>(
- new CustomProtocolHandler(m_profileAdapter)));
- }
-
- m_baseJobFactory = jobFactory.get();
-
- // Set up interceptors in the reverse order.
- std::unique_ptr<net::URLRequestJobFactory> topJobFactory = std::move(jobFactory);
- content::URLRequestInterceptorScopedVector::reverse_iterator i;
- for (i = m_requestInterceptors.rbegin(); i != m_requestInterceptors.rend(); ++i) {
- topJobFactory.reset(new net::URLRequestInterceptingJobFactory(std::move(topJobFactory),
- std::move(*i)));
- }
-
- m_requestInterceptors.clear();
-
- m_jobFactory = std::move(topJobFactory);
-
- m_urlRequestContext->set_job_factory(m_jobFactory.get());
-}
-
void ProfileIODataQt::regenerateJobFactory()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- Q_ASSERT(m_urlRequestContext);
- Q_ASSERT(m_jobFactory);
- Q_ASSERT(m_baseJobFactory);
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
m_updateJobFactory = false;
@@ -574,31 +176,13 @@ void ProfileIODataQt::regenerateJobFactory()
if (m_customUrlSchemes == m_installedCustomSchemes)
return;
- for (const QByteArray &scheme : qAsConst(m_installedCustomSchemes)) {
- m_baseJobFactory->SetProtocolHandler(scheme.toStdString(), nullptr);
- }
-
m_installedCustomSchemes = m_customUrlSchemes;
- for (const QByteArray &scheme : qAsConst(m_installedCustomSchemes)) {
- m_baseJobFactory->SetProtocolHandler(scheme.toStdString(),
- std::unique_ptr<net::URLRequestJobFactory::ProtocolHandler>(
- new CustomProtocolHandler(m_profileAdapter)));
- }
}
void ProfileIODataQt::setGlobalCertificateVerification()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
- if (m_useForGlobalCertificateVerification) {
-#if defined(USE_NSS_CERTS)
- // Set request context used by NSS for OCSP requests.
- net::SetURLRequestContextForNSSHttpIO(m_urlRequestContext.get());
-#endif
- if (!s_certNetFetcher)
- s_certNetFetcher = base::MakeRefCounted<net::CertNetFetcherImpl>();
- s_certNetFetcher->SetURLRequestContext(m_urlRequestContext.get());
- }
}
void ProfileIODataQt::setRequestContextData(content::ProtocolHandlerMap *protocolHandlers,
@@ -625,38 +209,28 @@ void ProfileIODataQt::setFullConfiguration()
m_dataPath = m_profileAdapter->dataPath();
}
+void ProfileIODataQt::resetNetworkContext()
+{
+ Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ setFullConfiguration();
+ content::BrowserContext::ForEachStoragePartition(
+ m_profile, base::BindRepeating([](content::StoragePartition *storage) {
+ auto storage_impl = static_cast<content::StoragePartitionImpl *>(storage);
+ storage_impl->ResetURLLoaderFactories();
+ storage_impl->ResetNetworkContext();
+ }));
+}
+
void ProfileIODataQt::requestStorageGeneration() {
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
if (m_initialized && !m_updateAllStorage) {
m_updateAllStorage = true;
- createProxyConfig();
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&ProfileIODataQt::generateAllStorage, m_weakPtr));
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&ProfileIODataQt::generateAllStorage, m_weakPtr));
}
}
-// TODO(miklocek): mojofy ProxyConfigServiceQt
-void ProfileIODataQt::createProxyConfig()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- const std::lock_guard<QRecursiveMutex> lock(m_mutex);
- // We must create the proxy config service on the UI loop on Linux because it
- // must synchronously run on the glib message loop. This will be passed to
- // the URLRequestContextStorage on the IO thread in GetURLRequestContext().
- Q_ASSERT(m_proxyConfigService == 0);
- net::ProxyConfigWithAnnotation initialConfig;
- ProxyPrefs::ConfigState initialConfigState = PrefProxyConfigTrackerImpl::ReadPrefConfig(
- m_profileAdapter->profile()->GetPrefs(), &initialConfig);
- m_proxyConfigService =
- new ProxyConfigServiceQt(
- net::ProxyResolutionService::CreateSystemProxyConfigService(
- base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})),
- initialConfig, initialConfigState);
- //pass interface to io thread
- m_proxyResolverFactoryInterface = ChromeMojoProxyResolverFactory::CreateWithSelfOwnedReceiver();
-}
-
void ProfileIODataQt::updateStorageSettings()
{
Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
@@ -664,11 +238,6 @@ void ProfileIODataQt::updateStorageSettings()
const std::lock_guard<QRecursiveMutex> lock(m_mutex);
setFullConfiguration();
- base::Token groupId = content::BrowserContext::GetServiceInstanceGroupFor(m_profile);
- if (file::GetUserDirForInstanceGroup(groupId) != toFilePath(m_profileAdapter->dataPath())) {
- file::ForgetServiceInstanceGroupUserDirAssociation(groupId);
- file::AssociateServiceInstanceGroupWithUserDir(groupId, toFilePath(m_profileAdapter->dataPath()));
- }
if (!m_pendingStorageRequestGeneration)
requestStorageGeneration();
}
@@ -726,8 +295,8 @@ void ProfileIODataQt::updateJobFactory()
if (m_initialized && !m_updateJobFactory) {
m_updateJobFactory = true;
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&ProfileIODataQt::regenerateJobFactory, m_weakPtr));
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&ProfileIODataQt::regenerateJobFactory, m_weakPtr));
}
}
@@ -751,6 +320,7 @@ bool ProfileIODataQt::isInterceptorDeprecated() const
QWebEngineUrlRequestInterceptor *ProfileIODataQt::acquireInterceptor()
{
+ Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
m_mutex.lock();
return m_requestInterceptor;
}
@@ -769,6 +339,7 @@ bool ProfileIODataQt::hasPageInterceptors()
void ProfileIODataQt::releaseInterceptor()
{
+ Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
m_mutex.unlock();
}
@@ -791,8 +362,8 @@ void ProfileIODataQt::updateUsedForGlobalCertificateVerification()
m_useForGlobalCertificateVerification = m_profileAdapter->isUsedForGlobalCertificateVerification();
if (m_useForGlobalCertificateVerification)
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::IO},
- base::BindOnce(&ProfileIODataQt::setGlobalCertificateVerification, m_weakPtr));
+ base::PostTask(FROM_HERE, {content::BrowserThread::IO},
+ base::BindOnce(&ProfileIODataQt::setGlobalCertificateVerification, m_weakPtr));
}
#if QT_CONFIG(ssl)
@@ -811,21 +382,55 @@ std::unique_ptr<net::ClientCertStore> ProfileIODataQt::CreateClientCertStore()
#endif
}
-void ProfileIODataQt::CreateRestrictedCookieManager(network::mojom::RestrictedCookieManagerRequest request,
- network::mojom::RestrictedCookieManagerRole role,
- const url::Origin &origin,
- bool is_service_worker,
- int32_t process_id,
- int32_t routing_id)
+network::mojom::NetworkContextParamsPtr ProfileIODataQt::CreateNetworkContextParams()
{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- m_restrictedCookieManagerBindings.AddBinding(
- std::make_unique<RestrictedCookieManagerQt>(
- m_weakPtr,
- role, urlRequestContext()->cookie_store(),
- &m_cookieSettings, origin,
- is_service_worker, process_id, routing_id),
- std::move(request));
+ updateStorageSettings();
+
+ network::mojom::NetworkContextParamsPtr network_context_params =
+ SystemNetworkContextManager::GetInstance()->CreateDefaultNetworkContextParams();
+
+ network_context_params->context_name = m_profile->profileAdapter()->storageName().toStdString();
+ network_context_params->user_agent = m_httpUserAgent.toStdString();
+ network_context_params->accept_language = m_httpAcceptLanguage.toStdString();
+
+ network_context_params->enable_referrers = true;
+ // Encrypted cookies requires os_crypt, which currently has issues for us on Linux.
+ network_context_params->enable_encrypted_cookies = false;
+
+ 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())
+ network_context_params->http_cache_path = toFilePath(m_httpCachePath);
+
+ if (m_persistentCookiesPolicy != ProfileAdapter::NoPersistentCookies && !m_dataPath.isEmpty()) {
+ base::FilePath cookie_path = toFilePath(m_dataPath);
+ cookie_path = cookie_path.AppendASCII("Cookies");
+ network_context_params->cookie_path = cookie_path;
+
+ network_context_params->restore_old_session_cookies = m_persistentCookiesPolicy == ProfileAdapter::ForcePersistentCookies;
+ network_context_params->persist_session_cookies = m_persistentCookiesPolicy != ProfileAdapter::NoPersistentCookies;
+ }
+ if (!m_dataPath.isEmpty()) {
+ network_context_params->http_server_properties_path = toFilePath(m_dataPath).AppendASCII("Network Persistent State");
+ network_context_params->transport_security_persister_path = toFilePath(m_dataPath);
+ }
+
+#if !BUILDFLAG(DISABLE_FTP_SUPPORT)
+ network_context_params->enable_ftp_url_support = true;
+#endif // !BUILDFLAG(DISABLE_FTP_SUPPORT)
+
+// network_context_params->enable_certificate_reporting = true;
+// network_context_params->enable_expect_ct_reporting = true;
+ network_context_params->enforce_chrome_ct_policy = false;
+ network_context_params->primary_network_context = m_useForGlobalCertificateVerification;
+
+ // Should be initialized with existing per-profile CORS access lists.
+ network_context_params->cors_origin_access_list =
+ m_profile->GetSharedCorsOriginAccessList()->GetOriginAccessList().CreateCorsOriginAccessPatternsList();
+
+ m_proxyConfigMonitor->AddToNetworkContextParams(network_context_params.get());
+
+ return network_context_params;
}
// static
diff --git a/src/core/profile_io_data_qt.h b/src/core/profile_io_data_qt.h
index ec0a3dac9..fcd209bf8 100644
--- a/src/core/profile_io_data_qt.h
+++ b/src/core/profile_io_data_qt.h
@@ -40,16 +40,13 @@
#ifndef PROFILE_IO_DATA_QT_H
#define PROFILE_IO_DATA_QT_H
-#include "profile_adapter.h"
#include "content/public/browser/browsing_data_remover.h"
-#include "content/public/common/url_loader_throttle.h"
#include "chrome/browser/profiles/profile.h"
-#include "chrome/browser/custom_handlers/protocol_handler_registry.h"
#include "extensions/buildflags/buildflags.h"
-#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "services/network/cookie_settings.h"
-#include "services/network/public/mojom/restricted_cookie_manager.mojom.h"
-#include "services/proxy_resolver/public/mojom/proxy_resolver.mojom.h"
+
+#include "net/proxy_config_monitor.h"
+#include "profile_adapter.h"
#include <QtCore/QString>
#include <QtCore/QPointer>
@@ -57,16 +54,7 @@
namespace net {
class ClientCertStore;
-class DhcpPacFileFetcherFactory;
-class HttpAuthPreferences;
-class HttpNetworkSession;
-class HostResolver;
-class NetworkDelegate;
-class ProxyConfigService;
class URLRequestContext;
-class URLRequestContextStorage;
-class URLRequestJobFactoryImpl;
-class TransportSecurityPersister;
}
namespace extensions {
@@ -108,22 +96,12 @@ public:
extensions::ExtensionSystemQt* GetExtensionSystem();
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
- ProtocolHandlerRegistry::IOThreadDelegate *protocolHandlerRegistryIOThreadDelegate()
- {
- return m_protocolHandlerRegistryIOThreadDelegate.get();
- }
-
void initializeOnIOThread();
void initializeOnUIThread(); // runs on ui thread
void shutdownOnUIThread(); // runs on ui thread
void cancelAllUrlRequests();
void generateAllStorage();
- void generateStorage();
- void generateCookieStore();
- void generateHttpCache();
- void generateUserAgent();
- void generateJobFactory();
void regenerateJobFactory();
bool canSetCookie(const QUrl &firstPartyUrl, const QByteArray &cookieLine, const QUrl &url) const;
bool canGetCookies(const QUrl &firstPartyUrl, const QUrl &url) const;
@@ -138,6 +116,7 @@ public:
void setRequestContextData(content::ProtocolHandlerMap *protocolHandlers,
content::URLRequestInterceptorScopedVector request_interceptors);
void setFullConfiguration(); // runs on ui thread
+ void resetNetworkContext(); // runs on ui thread
void updateStorageSettings(); // runs on ui thread
void updateUserAgent(); // runs on ui thread
void updateCookieStore(); // runs on ui thread
@@ -145,16 +124,10 @@ public:
void updateJobFactory(); // runs on ui thread
void updateRequestInterceptor(); // runs on ui thread
void requestStorageGeneration(); //runs on ui thread
- void createProxyConfig(); //runs on ui thread
void updateUsedForGlobalCertificateVerification(); // runs on ui thread
bool hasPageInterceptors();
- void CreateRestrictedCookieManager(network::mojom::RestrictedCookieManagerRequest request,
- network::mojom::RestrictedCookieManagerRole role,
- const url::Origin &origin,
- bool is_service_worker,
- int32_t process_id,
- int32_t routing_id);
+ network::mojom::NetworkContextParamsPtr CreateNetworkContextParams();
#if QT_CONFIG(ssl)
ClientCertificateStoreData *clientCertificateStoreData();
@@ -163,34 +136,23 @@ public:
static ProfileIODataQt *FromBrowserContext(content::BrowserContext *browser_context);
static ProfileIODataQt *FromResourceContext(content::ResourceContext *resource_context);
+ base::WeakPtr<ProfileIODataQt> getWeakPtrOnIOThread();
base::WeakPtr<ProfileIODataQt> getWeakPtrOnUIThread();
+ CookieMonsterDelegateQt *cookieDelegate() const { return m_cookieDelegate.get(); }
+
private:
void removeBrowsingDataRemoverObserver();
ProfileQt *m_profile;
- std::unique_ptr<net::URLRequestContextStorage> m_storage;
- std::unique_ptr<net::NetworkDelegate> m_networkDelegate;
std::unique_ptr<content::ResourceContext> m_resourceContext;
- std::unique_ptr<net::URLRequestContext> m_urlRequestContext;
- std::unique_ptr<net::HttpNetworkSession> m_httpNetworkSession;
- scoped_refptr<ProtocolHandlerRegistry::IOThreadDelegate>
- m_protocolHandlerRegistryIOThreadDelegate;
- std::unique_ptr<net::DhcpPacFileFetcherFactory> m_dhcpPacFileFetcherFactory;
- std::unique_ptr<net::HttpAuthPreferences> m_httpAuthPreferences;
- std::unique_ptr<net::URLRequestJobFactory> m_jobFactory;
- std::unique_ptr<net::TransportSecurityPersister> m_transportSecurityPersister;
- std::unique_ptr<net::HostResolver> m_hostResolver;
base::WeakPtr<ProfileIODataQt> m_weakPtr;
scoped_refptr<CookieMonsterDelegateQt> m_cookieDelegate;
content::URLRequestInterceptorScopedVector m_requestInterceptors;
content::ProtocolHandlerMap m_protocolHandlers;
- mojo::InterfacePtrInfo<proxy_resolver::mojom::ProxyResolverFactory> m_proxyResolverFactoryInterface;
- net::URLRequestJobFactoryImpl *m_baseJobFactory = nullptr;
- QAtomicPointer<net::ProxyConfigService> m_proxyConfigService;
QPointer<ProfileAdapter> m_profileAdapter; // never dereferenced in IO thread and it is passed by qpointer
ProfileAdapter::PersistentCookiesPolicy m_persistentCookiesPolicy;
- mojo::StrongBindingSet<network::mojom::RestrictedCookieManager> m_restrictedCookieManagerBindings;
+ std::unique_ptr<ProxyConfigMonitor> m_proxyConfigMonitor;
#if QT_CONFIG(ssl)
ClientCertificateStoreData *m_clientCertificateStoreData;
diff --git a/src/core/profile_qt.cpp b/src/core/profile_qt.cpp
index be55e7c49..748104312 100644
--- a/src/core/profile_qt.cpp
+++ b/src/core/profile_qt.cpp
@@ -41,10 +41,8 @@
#include "profile_adapter.h"
#include "browsing_data_remover_delegate_qt.h"
-#include "command_line_pref_store_qt.h"
#include "download_manager_delegate_qt.h"
#include "net/ssl_host_state_delegate_qt.h"
-#include "net/url_request_context_getter_qt.h"
#include "permission_manager_qt.h"
#include "platform_notification_service_qt.h"
#include "qtwebenginecoreglobal_p.h"
@@ -52,8 +50,10 @@
#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"
@@ -76,7 +76,6 @@
#if BUILDFLAG(ENABLE_EXTENSIONS)
#include "components/guest_view/browser/guest_view_manager.h"
-#include "extensions/browser/extension_protocols.h"
#include "extensions/browser/pref_names.h"
#include "extensions/browser/process_manager.h"
#include "extensions/common/constants.h"
@@ -145,16 +144,6 @@ bool ProfileQt::IsOffTheRecord()
return m_profileAdapter->isOffTheRecord();
}
-net::URLRequestContextGetter *ProfileQt::GetRequestContext()
-{
- return m_urlRequestContextGetter.get();
-}
-
-net::URLRequestContextGetter *ProfileQt::CreateMediaRequestContext()
-{
- return m_urlRequestContextGetter.get();
-}
-
content::ResourceContext *ProfileQt::GetResourceContext()
{
return m_profileIOData->resourceContext();
@@ -176,7 +165,7 @@ content::BrowserPluginGuestManager *ProfileQt::GetGuestManager()
storage::SpecialStoragePolicy *ProfileQt::GetSpecialStoragePolicy()
{
- QT_NOT_YET_IMPLEMENTED
+ // matches android_webview and chromecast
return nullptr;
}
@@ -221,26 +210,12 @@ content::PermissionControllerDelegate *ProfileQt::GetPermissionControllerDelegat
return m_permissionManager.get();
}
-net::URLRequestContextGetter *ProfileQt::CreateRequestContext(
- content::ProtocolHandlerMap *protocol_handlers,
- content::URLRequestInterceptorScopedVector request_interceptors)
+content::ClientHintsControllerDelegate *ProfileQt::GetClientHintsControllerDelegate()
{
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
- DCHECK(!m_urlRequestContextGetter.get());
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- extensions::InfoMap *extension_info_map = GetExtensionSystem()->info_map();
- (*protocol_handlers)[extensions::kExtensionScheme] =
- extensions::CreateExtensionProtocolHandler(IsOffTheRecord(), extension_info_map);
-#endif
-
- m_profileIOData->setRequestContextData(protocol_handlers, std::move(request_interceptors));
- m_profileIOData->updateStorageSettings();
- m_profileIOData->updateRequestInterceptor();
- m_urlRequestContextGetter = new URLRequestContextGetterQt(m_profileIOData.get());
- return m_urlRequestContextGetter.get();
+ return nullptr;
}
-content::ClientHintsControllerDelegate *ProfileQt::GetClientHintsControllerDelegate()
+content::StorageNotificationService *ProfileQt::GetStorageNotificationService()
{
return nullptr;
}
@@ -250,10 +225,22 @@ void ProfileQt::SetCorsOriginAccessListForOrigin(const url::Origin &source_origi
std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
base::OnceClosure closure)
{
+ auto barrier_closure = base::BarrierClosure(2, std::move(closure));
+
+ // Keep profile storage partitions' NetworkContexts synchronized.
+ auto profile_setter = base::MakeRefCounted<content::CorsOriginPatternSetter>(
+ source_origin,
+ content::CorsOriginPatternSetter::ClonePatterns(allow_patterns),
+ content::CorsOriginPatternSetter::ClonePatterns(block_patterns),
+ barrier_closure);
+ ForEachStoragePartition(this,
+ base::BindRepeating(&content::CorsOriginPatternSetter::SetLists,
+ base::RetainedRef(profile_setter.get())));
+
m_sharedCorsOriginAccessList->SetForOrigin(source_origin,
std::move(allow_patterns),
std::move(block_patterns),
- std::move(closure));
+ barrier_closure);
}
content::SharedCorsOriginAccessList *ProfileQt::GetSharedCorsOriginAccessList()
diff --git a/src/core/profile_qt.h b/src/core/profile_qt.h
index f5dc59717..59f5a8c21 100644
--- a/src/core/profile_qt.h
+++ b/src/core/profile_qt.h
@@ -44,7 +44,6 @@
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/resource_context.h"
#include "extensions/buildflags/buildflags.h"
-#include "net/url_request/url_request_context.h"
#include "pref_service_adapter.h"
#include "profile_io_data_qt.h"
#include <QtGlobal>
@@ -79,16 +78,12 @@ public:
base::FilePath GetPath() override;
bool IsOffTheRecord() override;
- net::URLRequestContextGetter *CreateMediaRequestContext() override;
content::ResourceContext *GetResourceContext() override;
content::DownloadManagerDelegate *GetDownloadManagerDelegate() override;
content::BrowserPluginGuestManager *GetGuestManager() override;
storage::SpecialStoragePolicy *GetSpecialStoragePolicy() override;
content::PushMessagingService *GetPushMessagingService() override;
content::SSLHostStateDelegate *GetSSLHostStateDelegate() override;
- net::URLRequestContextGetter *CreateRequestContext(
- content::ProtocolHandlerMap *protocol_handlers,
- content::URLRequestInterceptorScopedVector request_interceptors) override;
std::unique_ptr<content::ZoomLevelDelegate> CreateZoomLevelDelegate(
const base::FilePath &partition_path) override;
content::PermissionControllerDelegate * GetPermissionControllerDelegate() override;
@@ -96,6 +91,7 @@ public:
content::BackgroundSyncController *GetBackgroundSyncController() override;
content::BrowsingDataRemoverDelegate *GetBrowsingDataRemoverDelegate() override;
content::ClientHintsControllerDelegate *GetClientHintsControllerDelegate() override;
+ content::StorageNotificationService *GetStorageNotificationService() override;
void SetCorsOriginAccessListForOrigin(const url::Origin &source_origin,
std::vector<network::mojom::CorsOriginPatternPtr> allow_patterns,
std::vector<network::mojom::CorsOriginPatternPtr> block_patterns,
@@ -106,9 +102,8 @@ public:
// Profile implementation:
PrefService *GetPrefs() override;
const PrefService *GetPrefs() const override;
- net::URLRequestContextGetter *GetRequestContext() override;
- void Initialize();
+ void Initialize();
ProfileAdapter *profileAdapter() { return m_profileAdapter; }
content::PlatformNotificationService *platformNotificationService();
@@ -132,7 +127,6 @@ private:
friend class ContentBrowserClientQt;
friend class ProfileIODataQt;
friend class WebContentsAdapter;
- scoped_refptr<net::URLRequestContextGetter> m_urlRequestContextGetter;
std::unique_ptr<BrowsingDataRemoverDelegateQt> m_removerDelegate;
std::unique_ptr<PermissionManagerQt> m_permissionManager;
std::unique_ptr<SSLHostStateDelegateQt> m_sslHostStateDelegate;
diff --git a/src/core/qtwebengine.gni b/src/core/qtwebengine.gni
index 9106e4d56..f17f28495 100644
--- a/src/core/qtwebengine.gni
+++ b/src/core/qtwebengine.gni
@@ -20,6 +20,7 @@ deps = [
"//components/cdm/renderer",
"//components/error_page/common",
"//components/keyed_service/content",
+ "//components/navigation_interception",
"//components/network_hints/browser",
"//components/network_hints/common",
"//components/network_hints/renderer",
diff --git a/src/core/qtwebengine_sources.gni b/src/core/qtwebengine_sources.gni
index 011a143b5..9c65fa690 100644
--- a/src/core/qtwebengine_sources.gni
+++ b/src/core/qtwebengine_sources.gni
@@ -49,7 +49,9 @@ source_set("qtwebengine_sources") {
"//build:branding_buildflags",
"//chrome/common:buildflags",
"//components/nacl/common:buildflags",
+ "//components/plugins/renderer/",
"//extensions/buildflags:buildflags",
+ "//rlz/buildflags:buildflags",
"//third_party/blink/public/mojom:mojom_platform",
]
@@ -63,10 +65,14 @@ source_set("qtwebengine_sources") {
"//chrome/browser/media/webrtc/desktop_media_list.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",
+ "//chrome/browser/prefs/chrome_command_line_pref_store.h",
"//chrome/browser/profiles/profile.cc",
"//chrome/browser/profiles/profile.h",
"//chrome/browser/ui/webui/devtools_ui.cc",
"//chrome/browser/ui/webui/devtools_ui.h",
+ "//chrome/browser/ui/webui/devtools_ui_data_source.cc",
+ "//chrome/browser/ui/webui/devtools_ui_data_source.h",
"//chrome/browser/ui/webui/quota_internals/quota_internals_handler.cc",
"//chrome/browser/ui/webui/quota_internals/quota_internals_handler.h",
"//chrome/browser/ui/webui/quota_internals/quota_internals_proxy.cc",
@@ -128,8 +134,8 @@ source_set("qtwebengine_sources") {
if (is_linux) {
sources += [
- "//chrome/browser/ui/webui/sandbox_internals_ui.cc",
- "//chrome/browser/ui/webui/sandbox_internals_ui.h",
+ "//chrome/browser/ui/webui/sandbox/sandbox_internals_ui.cc",
+ "//chrome/browser/ui/webui/sandbox/sandbox_internals_ui.h",
]
}
diff --git a/src/core/quota_permission_context_qt.cpp b/src/core/quota_permission_context_qt.cpp
index a502e7fc8..94645b237 100644
--- a/src/core/quota_permission_context_qt.cpp
+++ b/src/core/quota_permission_context_qt.cpp
@@ -66,7 +66,7 @@ void QuotaPermissionContextQt::RequestQuotaPermission(const StorageQuotaParams &
}
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) {
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(&QuotaPermissionContextQt::RequestQuotaPermission, this,
params, render_process_id, callback));
@@ -97,7 +97,7 @@ void QuotaPermissionContextQt::dispatchCallbackOnIOThread(const PermissionCallba
return;
if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)) {
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, {content::BrowserThread::IO},
base::BindOnce(&QuotaPermissionContextQt::dispatchCallbackOnIOThread,
this, callback, response));
diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp
index 7a5118837..c1b1791cf 100644
--- a/src/core/render_widget_host_view_qt.cpp
+++ b/src/core/render_widget_host_view_qt.cpp
@@ -362,6 +362,10 @@ RenderWidgetHostViewQt::~RenderWidgetHostViewQt()
void RenderWidgetHostViewQt::setDelegate(RenderWidgetHostViewQtDelegate* delegate)
{
m_delegate.reset(delegate);
+ if (m_deferredShow) {
+ m_deferredShow = false;
+ Show();
+ }
visualPropertiesChanged();
}
@@ -468,16 +472,21 @@ void RenderWidgetHostViewQt::CopyFromSurface(const gfx::Rect &src_rect,
void RenderWidgetHostViewQt::Show()
{
- m_delegate->show();
+ if (m_delegate)
+ m_delegate->show();
+ else
+ m_deferredShow = true;
}
void RenderWidgetHostViewQt::Hide()
{
+ Q_ASSERT(m_delegate);
m_delegate->hide();
}
bool RenderWidgetHostViewQt::IsShowing()
{
+ Q_ASSERT(m_delegate);
return m_delegate->isVisible();
}
@@ -506,7 +515,7 @@ void RenderWidgetHostViewQt::UpdateBackgroundColor()
}
// Return value indicates whether the mouse is locked successfully or not.
-bool RenderWidgetHostViewQt::LockMouse()
+bool RenderWidgetHostViewQt::LockMouse(bool)
{
m_previousMousePosition = QCursor::pos();
m_delegate->lockMouse();
@@ -751,10 +760,6 @@ gfx::Rect RenderWidgetHostViewQt::GetBoundsInRootWindow()
return m_windowRectInDips;
}
-void RenderWidgetHostViewQt::ClearCompositorFrame()
-{
-}
-
void RenderWidgetHostViewQt::OnUpdateTextInputStateCalled(content::TextInputManager *text_input_manager, RenderWidgetHostViewBase *updated_view, bool did_update_state)
{
Q_UNUSED(text_input_manager);
@@ -827,7 +832,7 @@ void RenderWidgetHostViewQt::OnTextSelectionChanged(content::TextInputManager *t
#if defined(USE_OZONE)
if (!selection->selected_text().empty() && selection->user_initiated()) {
// Set the CLIPBOARD_TYPE_SELECTION to the ui::Clipboard.
- ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardType::kSelection);
+ ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kSelection);
clipboard_writer.WriteText(selection->selected_text());
}
#endif // defined(USE_OZONE)
@@ -1706,6 +1711,7 @@ void RenderWidgetHostViewQt::handlePointerEvent(T *event)
if ((webEvent.GetType() == blink::WebInputEvent::kMouseDown || webEvent.GetType() == blink::WebInputEvent::kMouseUp)
&& webEvent.button == blink::WebMouseEvent::Button::kNoButton) {
// Blink can only handle the 3 main mouse-buttons and may assert when processing mouse-down for no button.
+ LOG(INFO) << "Unhandled mouse button";
return;
}
@@ -1874,9 +1880,9 @@ void RenderWidgetHostViewQt::OnRenderFrameMetadataChangedAfterActivation()
gfx::SizeF contentsSize = metadata.root_layer_size;
std::swap(m_lastScrollOffset, scrollOffset);
std::swap(m_lastContentsSize, contentsSize);
- if (scrollOffset != m_lastScrollOffset)
+ if (m_adapterClient && scrollOffset != m_lastScrollOffset)
m_adapterClient->updateScrollPosition(toQt(m_lastScrollOffset));
- if (contentsSize != m_lastContentsSize)
+ if (m_adapterClient && contentsSize != m_lastContentsSize)
m_adapterClient->updateContentsSize(toQt(m_lastContentsSize));
}
diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h
index dc6ccc8df..41ce50b34 100644
--- a/src/core/render_widget_host_view_qt.h
+++ b/src/core/render_widget_host_view_qt.h
@@ -141,7 +141,7 @@ public:
bool IsShowing() override;
gfx::Rect GetViewBounds() override;
void UpdateBackgroundColor() override;
- bool LockMouse() override;
+ bool LockMouse(bool) override;
void UnlockMouse() override;
void UpdateCursor(const content::WebCursor&) override;
void DisplayCursor(const content::WebCursor&) override;
@@ -162,7 +162,6 @@ public:
void GetScreenInfo(content::ScreenInfo *results) override;
gfx::Rect GetBoundsInRootWindow() override;
void ProcessAckedTouchEvent(const content::TouchEventWithLatencyInfo &touch, content::InputEventAckState ack_result) override;
- void ClearCompositorFrame() override;
void SetNeedsBeginFrames(bool needs_begin_frames) override;
void SetWantsAnimateOnlyBeginFrames() override;
viz::SurfaceId GetCurrentSurfaceId() const override;
@@ -273,6 +272,7 @@ private:
const bool m_enableViz;
bool m_visible;
bool m_needsBeginFrames;
+ bool m_deferredShow = false;
DelegatedFrameHostClientQt m_delegatedFrameHostClient{this};
std::unique_ptr<content::DelegatedFrameHost> m_delegatedFrameHost;
std::unique_ptr<ui::Layer> m_rootLayer;
diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp
index b9b199087..f7c8a497b 100644
--- a/src/core/renderer/content_renderer_client_qt.cpp
+++ b/src/core/renderer/content_renderer_client_qt.cpp
@@ -95,8 +95,15 @@
#include "extensions/extensions_renderer_client_qt.h"
#endif //ENABLE_EXTENSIONS
+#if BUILDFLAG(ENABLE_PLUGINS)
+#include "plugins/loadable_plugin_placeholder_qt.h"
+#include "plugins/plugin_placeholder_qt.h"
+#include "content/common/frame_messages.h"
+#endif // ENABLE_PLUGINS
+
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/connector.h"
+#include "services/service_manager/public/cpp/service_binding.h"
#include "components/grit/components_resources.h"
@@ -114,7 +121,6 @@ namespace QtWebEngineCore {
static const char kHttpErrorDomain[] = "http";
ContentRendererClientQt::ContentRendererClientQt()
- : m_serviceBinding(this)
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
extensions::ExtensionsClient::Set(extensions::ExtensionsClientQt::GetInstance());
@@ -122,14 +128,11 @@ ContentRendererClientQt::ContentRendererClientQt()
#endif
}
-ContentRendererClientQt::~ContentRendererClientQt()
-{
-}
+ContentRendererClientQt::~ContentRendererClientQt() {}
void ContentRendererClientQt::RenderThreadStarted()
{
content::RenderThread *renderThread = content::RenderThread::Get();
- (void)GetConnector();
m_renderThreadObserver.reset(new RenderThreadObserverQt());
m_visitedLinkSlave.reset(new visitedlink::VisitedLinkSlave);
m_webCacheImpl.reset(new web_cache::WebCacheImpl());
@@ -137,10 +140,9 @@ void ContentRendererClientQt::RenderThreadStarted()
m_prescientNetworkingDispatcher.reset(new network_hints::PrescientNetworkingDispatcher());
auto registry = std::make_unique<service_manager::BinderRegistry>();
- registry->AddInterface(m_visitedLinkSlave->GetBindCallback(),
- base::ThreadTaskRunnerHandle::Get());
+ registry->AddInterface(m_visitedLinkSlave->GetBindCallback(), base::ThreadTaskRunnerHandle::Get());
content::ChildThread::Get()->GetServiceManagerConnection()->AddConnectionFilter(
- std::make_unique<content::SimpleConnectionFilter>(std::move(registry)));
+ std::make_unique<content::SimpleConnectionFilter>(std::move(registry)));
renderThread->AddObserver(m_renderThreadObserver.data());
renderThread->AddObserver(UserResourceController::instance());
@@ -151,34 +153,35 @@ void ContentRendererClientQt::RenderThreadStarted()
#endif
// Allow XMLHttpRequests from qrc to file.
+ // ### consider removing for Qt6
blink::WebURL qrc(blink::KURL("qrc:"));
blink::WebString file(blink::WebString::FromASCII("file"));
- blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(qrc, file, blink::WebString(), 0,
- network::mojom::CorsDomainMatchMode::kAllowSubdomains,
- network::mojom::CorsPortMatchMode::kAllowAnyPort,
- network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
+ blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(
+ qrc, file, blink::WebString(), 0, network::mojom::CorsDomainMatchMode::kAllowSubdomains,
+ network::mojom::CorsPortMatchMode::kAllowAnyPort,
+ network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
#if BUILDFLAG(ENABLE_EXTENSIONS)
// Allow the pdf viewer extension to access chrome resources
blink::WebURL pdfViewerExtension(blink::KURL("chrome-extension://mhjfbmdgcfjbbpaeojofohoefgiehjai"));
blink::WebString chromeResources(blink::WebString::FromASCII("chrome"));
- blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(pdfViewerExtension, chromeResources, blink::WebString(), 0,
- network::mojom::CorsDomainMatchMode::kAllowSubdomains,
- network::mojom::CorsPortMatchMode::kAllowAnyPort,
- network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
+ blink::WebSecurityPolicy::AddOriginAccessAllowListEntry(
+ pdfViewerExtension, chromeResources, blink::WebString(), 0,
+ network::mojom::CorsDomainMatchMode::kAllowSubdomains, network::mojom::CorsPortMatchMode::kAllowAnyPort,
+ network::mojom::CorsOriginAccessMatchPriority::kDefaultPriority);
ExtensionsRendererClientQt::GetInstance()->RenderThreadStarted();
#endif
}
-void ContentRendererClientQt::RenderViewCreated(content::RenderView* render_view)
+void ContentRendererClientQt::RenderViewCreated(content::RenderView *render_view)
{
// RenderViewObservers destroy themselves with their RenderView.
new RenderViewObserverQt(render_view);
UserResourceController::instance()->renderViewCreated(render_view);
}
-void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_frame)
+void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame *render_frame)
{
QtWebEngineCore::RenderFrameObserverQt *render_frame_observer =
new QtWebEngineCore::RenderFrameObserverQt(render_frame, m_webCacheImpl.data());
@@ -195,9 +198,7 @@ void ContentRendererClientQt::RenderFrameCreated(content::RenderFrame* render_fr
new SpellCheckProvider(render_frame, m_spellCheck.data(), this);
#endif
#if QT_CONFIG(webengine_printing_and_pdf)
- new printing::PrintRenderFrameHelper(
- render_frame,
- base::WrapUnique(new PrintWebViewHelperDelegateQt()));
+ new printing::PrintRenderFrameHelper(render_frame, base::WrapUnique(new PrintWebViewHelperDelegateQt()));
#endif // QT_CONFIG(webengine_printing_and_pdf)
#if BUILDFLAG(ENABLE_EXTENSIONS)
auto registry = std::make_unique<service_manager::BinderRegistry>();
@@ -255,29 +256,28 @@ bool ContentRendererClientQt::ShouldSuppressErrorPage(content::RenderFrame *fram
void ContentRendererClientQt::PrepareErrorPage(content::RenderFrame *renderFrame,
const blink::WebURLError &web_error,
const std::string &httpMethod,
- bool ignoring_cache,
std::string *errorHtml)
{
- Q_UNUSED(ignoring_cache);
- GetNavigationErrorStringsInternal(renderFrame, httpMethod,
- error_page::Error::NetError(web_error.url(), web_error.reason(), web_error.has_copy_in_cache()),
- errorHtml);
+ GetNavigationErrorStringsInternal(
+ renderFrame, httpMethod,
+ error_page::Error::NetError(web_error.url(), web_error.reason(), web_error.has_copy_in_cache()), errorHtml);
}
void ContentRendererClientQt::PrepareErrorPageForHttpStatusError(content::RenderFrame *renderFrame,
const GURL &unreachable_url,
const std::string &httpMethod,
- bool ignoring_cache,
int http_status,
std::string *errorHtml)
{
- Q_UNUSED(ignoring_cache);
GetNavigationErrorStringsInternal(renderFrame, httpMethod,
error_page::Error::HttpError(unreachable_url, http_status),
errorHtml);
}
-void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderFrame *renderFrame, const std::string &httpMethod, const error_page::Error &error, std::string *errorHtml)
+void ContentRendererClientQt::GetNavigationErrorStringsInternal(content::RenderFrame *renderFrame,
+ const std::string &httpMethod,
+ const error_page::Error &error,
+ std::string *errorHtml)
{
Q_UNUSED(renderFrame)
const bool isPost = QByteArray::fromStdString(httpMethod) == QByteArrayLiteral("POST");
@@ -322,42 +322,67 @@ blink::WebPrescientNetworking *ContentRendererClientQt::GetPrescientNetworking()
return m_prescientNetworkingDispatcher.get();
}
-bool ContentRendererClientQt::OverrideCreatePlugin(
- content::RenderFrame* render_frame,
- const blink::WebPluginParams& params, blink::WebPlugin** plugin)
+bool ContentRendererClientQt::OverrideCreatePlugin(content::RenderFrame *render_frame,
+ const blink::WebPluginParams &params,
+ blink::WebPlugin **plugin)
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
if (!ExtensionsRendererClientQt::GetInstance()->OverrideCreatePlugin(render_frame, params))
return false;
#endif //ENABLE_EXTENSIONS
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+ chrome::mojom::PluginInfoPtr plugin_info = chrome::mojom::PluginInfo::New();
+ content::WebPluginInfo info;
+ std::string mime_type;
+ bool found = false;
+
+ render_frame->Send(new FrameHostMsg_GetPluginInfo(render_frame->GetRoutingID(), params.url,
+ render_frame->GetWebFrame()->Top()->GetSecurityOrigin(),
+ params.mime_type.Utf8(), &found, &info, &mime_type));
+ if (!found) {
+ *plugin = CreatePlugin(render_frame, params, *plugin_info);
+ return true;
+ }
+#endif // BUILDFLAG(ENABLE_PLUGINS)
return content::ContentRendererClient::OverrideCreatePlugin(render_frame, params, plugin);
}
-content::BrowserPluginDelegate* ContentRendererClientQt::CreateBrowserPluginDelegate(content::RenderFrame *render_frame,
+#if BUILDFLAG(ENABLE_PLUGINS)
+// static
+blink::WebPlugin* ContentRendererClientQt::CreatePlugin(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& original_params,
+ const chrome::mojom::PluginInfo& plugin_info)
+{
+ // If the browser plugin is to be enabled, this should be handled by the
+ // renderer, so the code won't reach here due to the early exit in OverrideCreatePlugin.
+ return LoadablePluginPlaceholderQt::CreateLoadableMissingPlugin(render_frame, original_params)->plugin();
+}
+#endif //BUILDFLAG(ENABLE_PLUGINS)
+
+content::BrowserPluginDelegate *ContentRendererClientQt::CreateBrowserPluginDelegate(content::RenderFrame *render_frame,
const content::WebPluginInfo &info,
const std::string &mime_type,
const GURL &original_url)
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
- return ExtensionsRendererClientQt::GetInstance()->CreateBrowserPluginDelegate(render_frame, info, mime_type, original_url);
+ return ExtensionsRendererClientQt::GetInstance()->CreateBrowserPluginDelegate(render_frame, info, mime_type,
+ original_url);
#else
return nullptr;
#endif
}
-void ContentRendererClientQt::OnBindInterface(const service_manager::BindSourceInfo &remote_info,
- const std::string& name,
- mojo::ScopedMessagePipeHandle handle)
+void ContentRendererClientQt::BindReceiverOnMainThread(mojo::GenericPendingReceiver receiver)
{
- Q_UNUSED(remote_info);
- m_registry.TryBindInterface(name, &handle);
+ std::string interface_name = *receiver.interface_name();
+ auto pipe = receiver.PassPipe();
+ m_registry.TryBindInterface(interface_name, &pipe);
}
void ContentRendererClientQt::GetInterface(const std::string &interface_name, mojo::ScopedMessagePipeHandle interface_pipe)
{
- m_serviceBinding.GetConnector()->BindInterface(
- service_manager::ServiceFilter::ByName("qtwebengine"),
- interface_name, std::move(interface_pipe));
+ content::RenderThread::Get()->BindHostReceiver(mojo::GenericPendingReceiver(interface_name, std::move(interface_pipe)));
}
// The following is based on chrome/renderer/media/chrome_key_systems.cc:
@@ -367,7 +392,7 @@ void ContentRendererClientQt::GetInterface(const std::string &interface_name, mo
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
// External Clear Key (used for testing).
-static void AddExternalClearKey(std::vector<std::unique_ptr<media::KeySystemProperties>>* concrete_key_systems)
+static void AddExternalClearKey(std::vector<std::unique_ptr<media::KeySystemProperties>> *concrete_key_systems)
{
// TODO(xhwang): Move these into an array so we can use a for loop to add
// supported key systems below.
@@ -403,57 +428,58 @@ static void AddExternalClearKey(std::vector<std::unique_ptr<media::KeySystemProp
}
concrete_key_systems->emplace_back(
- new cdm::ExternalClearKeyProperties(kExternalClearKeyKeySystem));
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyKeySystem));
// Add support of decrypt-only mode in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyDecryptOnlyKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyDecryptOnlyKeySystem));
// A key system that triggers various types of messages in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyMessageTypeTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyMessageTypeTestKeySystem));
// A key system that triggers the FileIO test in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyFileIOTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyFileIOTestKeySystem));
// A key system that triggers the output protection test in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyOutputProtectionTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyOutputProtectionTestKeySystem));
// A key system that triggers the platform verification test in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyPlatformVerificationTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyPlatformVerificationTestKeySystem));
// A key system that Chrome thinks is supported by ClearKeyCdm, but actually
// will be refused by ClearKeyCdm. This is to test the CDM initialization
// failure case.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyInitializeFailKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyInitializeFailKeySystem));
// A key system that triggers a crash in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyCrashKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyCrashKeySystem));
// A key system that triggers the verify host files test in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyVerifyCdmHostTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyVerifyCdmHostTestKeySystem));
// A key system that fetches the Storage ID in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyStorageIdTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyStorageIdTestKeySystem));
// A key system that is registered with a different CDM GUID.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyDifferentGuidTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyDifferentGuidTestKeySystem));
// A key system that triggers CDM Proxy test in ClearKeyCdm.
- concrete_key_systems->emplace_back(new cdm::ExternalClearKeyProperties(
- kExternalClearKeyCdmProxyTestKeySystem));
+ concrete_key_systems->emplace_back(
+ new cdm::ExternalClearKeyProperties(kExternalClearKeyCdmProxyTestKeySystem));
}
#if BUILDFLAG(ENABLE_WIDEVINE)
-static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoCodec> &supported_video_codecs, bool is_secure)
+static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoCodec> &supported_video_codecs,
+ bool is_secure)
{
media::SupportedCodecs supported_codecs = media::EME_CODEC_NONE;
@@ -469,7 +495,7 @@ static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoC
supported_codecs |= media::EME_CODEC_FLAC;
#if BUILDFLAG(USE_PROPRIETARY_CODECS)
supported_codecs |= media::EME_CODEC_AAC;
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
}
// Video codecs are determined by what was registered for the CDM.
@@ -486,7 +512,7 @@ static media::SupportedCodecs GetSupportedCodecs(const std::vector<media::VideoC
case media::VideoCodec::kCodecH264:
supported_codecs |= media::EME_CODEC_AVC1;
break;
-#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
+#endif // BUILDFLAG(USE_PROPRIETARY_CODECS)
default:
DVLOG(1) << "Unexpected supported codec: " << GetCodecName(codec);
break;
@@ -505,13 +531,11 @@ static void AddWidevine(std::vector<std::unique_ptr<media::KeySystemProperties>>
}
// Codecs and encryption schemes.
- auto codecs =
- GetSupportedCodecs(capability->video_codecs, /*is_secure=*/false);
- const auto& encryption_schemes = capability->encryption_schemes;
+ auto codecs = GetSupportedCodecs(capability->video_codecs, /*is_secure=*/false);
+ const auto &encryption_schemes = capability->encryption_schemes;
auto hw_secure_codecs = GetSupportedCodecs(capability->hw_secure_video_codecs,
/*is_secure=*/true);
- const auto& hw_secure_encryption_schemes =
- capability->hw_secure_encryption_schemes;
+ const auto &hw_secure_encryption_schemes = capability->hw_secure_encryption_schemes;
// Robustness.
using Robustness = cdm::WidevineKeySystemProperties::Robustness;
@@ -574,22 +598,13 @@ void ContentRendererClientQt::WillSendRequest(blink::WebLocalFrame *frame,
bool *attach_same_site_cookies)
{
#if BUILDFLAG(ENABLE_EXTENSIONS)
- ExtensionsRendererClientQt::GetInstance()->WillSendRequest(frame, transition_type, url, initiator_origin, new_url, attach_same_site_cookies);
+ ExtensionsRendererClientQt::GetInstance()->WillSendRequest(frame, transition_type, url, initiator_origin, new_url,
+ attach_same_site_cookies);
if (!new_url->is_empty())
return;
#endif
- content::ContentRendererClient::WillSendRequest(frame, transition_type, url, initiator_origin, new_url, attach_same_site_cookies);
-}
-
-void ContentRendererClientQt::CreateRendererService(service_manager::mojom::ServiceRequest service_request)
-{
- DCHECK(!m_serviceBinding.is_bound());
- m_serviceBinding.Bind(std::move(service_request));
-}
-
-service_manager::Connector* ContentRendererClientQt::GetConnector()
-{
- return m_serviceBinding.GetConnector();
+ content::ContentRendererClient::WillSendRequest(frame, transition_type, url, initiator_origin, new_url,
+ attach_same_site_cookies);
}
-} // namespace
+} // namespace QtWebEngineCore
diff --git a/src/core/renderer/content_renderer_client_qt.h b/src/core/renderer/content_renderer_client_qt.h
index a13d16b5c..da70d29a8 100644
--- a/src/core/renderer/content_renderer_client_qt.h
+++ b/src/core/renderer/content_renderer_client_qt.h
@@ -43,10 +43,13 @@
#include "content/public/renderer/content_renderer_client.h"
#include "components/spellcheck/spellcheck_buildflags.h"
#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connector.h"
#include "services/service_manager/public/cpp/local_interface_provider.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
+#include "ppapi/buildflags/buildflags.h"
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+#include "qtwebengine/browser/plugin.mojom.h"
+#include "third_party/blink/public/web/web_plugin_params.h"
+#endif
#include <QScopedPointer>
@@ -70,13 +73,17 @@ class WebCacheImpl;
class SpellCheck;
#endif
+namespace content {
+struct WebPluginInfo;
+}
+
namespace QtWebEngineCore {
class RenderThreadObserverQt;
-class ContentRendererClientQt : public content::ContentRendererClient
- , public service_manager::Service
- , public service_manager::LocalInterfaceProvider
+class ContentRendererClientQt
+ : public content::ContentRendererClient
+ , public service_manager::LocalInterfaceProvider
{
public:
ContentRendererClientQt();
@@ -85,34 +92,35 @@ public:
// content::ContentRendererClient:
void RenderThreadStarted() override;
void RenderViewCreated(content::RenderView *render_view) override;
- void RenderFrameCreated(content::RenderFrame* render_frame) override;
+ void RenderFrameCreated(content::RenderFrame *render_frame) override;
bool ShouldSuppressErrorPage(content::RenderFrame *, const GURL &) override;
bool HasErrorPage(int http_status_code) override;
void PrepareErrorPage(content::RenderFrame *render_frame,
const blink::WebURLError &error,
const std::string &http_method,
- bool ignoring_cache,
std::string *error_html) override;
void PrepareErrorPageForHttpStatusError(content::RenderFrame *render_frame,
const GURL &unreachable_url,
const std::string &http_method,
- bool ignoring_cache,
int http_status,
std::string *error_html) override;
uint64_t VisitedLinkHash(const char *canonical_url, size_t length) override;
bool IsLinkVisited(uint64_t linkHash) override;
- blink::WebPrescientNetworking* GetPrescientNetworking() override;
- void AddSupportedKeySystems(std::vector<std::unique_ptr<media::KeySystemProperties>>* key_systems) override;
+ blink::WebPrescientNetworking *GetPrescientNetworking() override;
+ void AddSupportedKeySystems(std::vector<std::unique_ptr<media::KeySystemProperties>> *key_systems) override;
void RunScriptsAtDocumentStart(content::RenderFrame *render_frame) override;
void RunScriptsAtDocumentEnd(content::RenderFrame *render_frame) override;
void RunScriptsAtDocumentIdle(content::RenderFrame *render_frame) override;
- bool OverrideCreatePlugin(content::RenderFrame* render_frame,
- const blink::WebPluginParams& params, blink::WebPlugin** plugin) override;
- content::BrowserPluginDelegate* CreateBrowserPluginDelegate(content::RenderFrame* render_frame,
- const content::WebPluginInfo& info, const std::string& mime_type, const GURL& original_url) override;
+ bool OverrideCreatePlugin(content::RenderFrame *render_frame,
+ const blink::WebPluginParams &params,
+ blink::WebPlugin **plugin) override;
+ content::BrowserPluginDelegate *CreateBrowserPluginDelegate(content::RenderFrame *render_frame,
+ const content::WebPluginInfo &info,
+ const std::string &mime_type,
+ const GURL &original_url) override;
void WillSendRequest(blink::WebLocalFrame *frame,
ui::PageTransition transition_type,
@@ -121,24 +129,23 @@ public:
GURL *new_url,
bool *attach_same_site_cookies) override;
- void CreateRendererService(service_manager::mojom::ServiceRequest service_request) override;
+ void BindReceiverOnMainThread(mojo::GenericPendingReceiver receiver) override;
+
+#if BUILDFLAG(ENABLE_PLUGINS)
+ static blink::WebPlugin* CreatePlugin(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ const chrome::mojom::PluginInfo& plugin_info);
+#endif
private:
#if BUILDFLAG(ENABLE_SPELLCHECK)
void InitSpellCheck();
#endif
- service_manager::Connector *GetConnector();
-
- // service_manager::Service:
- void OnBindInterface(const service_manager::BindSourceInfo &remote_info,
- const std::string &name,
- mojo::ScopedMessagePipeHandle handle) override;
-
// service_manager::LocalInterfaceProvider:
- void GetInterface(const std::string& name, mojo::ScopedMessagePipeHandle request_handle) override;
+ void GetInterface(const std::string &name, mojo::ScopedMessagePipeHandle request_handle) override;
- void GetNavigationErrorStringsInternal(content::RenderFrame* renderFrame, const std::string &httpMethod,
- const error_page::Error& error, std::string* errorHtml);
+ void GetNavigationErrorStringsInternal(content::RenderFrame *renderFrame, const std::string &httpMethod,
+ const error_page::Error &error, std::string *errorHtml);
QScopedPointer<RenderThreadObserverQt> m_renderThreadObserver;
QScopedPointer<visitedlink::VisitedLinkSlave> m_visitedLinkSlave;
@@ -147,8 +154,6 @@ private:
QScopedPointer<SpellCheck> m_spellCheck;
#endif
- service_manager::mojom::ConnectorRequest m_connectorRequest;
- service_manager::ServiceBinding m_serviceBinding;
service_manager::BinderRegistry m_registry;
std::unique_ptr<network_hints::PrescientNetworkingDispatcher> m_prescientNetworkingDispatcher;
diff --git a/src/core/renderer/content_settings_observer_qt.cpp b/src/core/renderer/content_settings_observer_qt.cpp
index a9e89dfee..fc7019367 100644
--- a/src/core/renderer/content_settings_observer_qt.cpp
+++ b/src/core/renderer/content_settings_observer_qt.cpp
@@ -63,40 +63,37 @@ bool IsUniqueFrame(blink::WebFrame *frame)
frame->Top()->GetSecurityOrigin().IsUnique();
}
-} // namespace
+} // namespace
namespace QtWebEngineCore {
ContentSettingsObserverQt::ContentSettingsObserverQt(content::RenderFrame *render_frame)
- : content::RenderFrameObserver(render_frame)
- , content::RenderFrameObserverTracker<ContentSettingsObserverQt>(render_frame)
- , m_currentRequestId(0)
+ : content::RenderFrameObserver(render_frame)
+ , content::RenderFrameObserverTracker<ContentSettingsObserverQt>(render_frame)
+ , m_currentRequestId(0)
{
ClearBlockedContentSettings();
render_frame->GetWebFrame()->SetContentSettingsClient(this);
}
-ContentSettingsObserverQt::~ContentSettingsObserverQt() {
-}
+ContentSettingsObserverQt::~ContentSettingsObserverQt() {}
-bool ContentSettingsObserverQt::OnMessageReceived(const IPC::Message& message)
+bool ContentSettingsObserverQt::OnMessageReceived(const IPC::Message &message)
{
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(ContentSettingsObserverQt, message)
- IPC_MESSAGE_HANDLER(QtWebEngineMsg_RequestFileSystemAccessAsyncResponse,
- OnRequestFileSystemAccessAsyncResponse)
- IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_MESSAGE_HANDLER(QtWebEngineMsg_RequestFileSystemAccessAsyncResponse, OnRequestFileSystemAccessAsyncResponse)
+ IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
-void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition /*transition*/)
+void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool is_same_document_navigation, ui::PageTransition /*transition*/)
{
- blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
+ blink::WebLocalFrame *frame = render_frame()->GetWebFrame();
if (frame->Parent())
- return; // Not a top-level navigation.
+ return; // Not a top-level navigation.
if (!is_same_document_navigation)
ClearBlockedContentSettings();
@@ -104,8 +101,7 @@ void ContentSettingsObserverQt::DidCommitProvisionalLoad(bool is_same_document_n
GURL url = frame->GetDocument().Url();
// If we start failing this DCHECK, please makes sure we don't regress
// this bug: http://code.google.com/p/chromium/issues/detail?id=79304
- DCHECK(frame->GetDocument().GetSecurityOrigin().ToString() == "null" ||
- !url.SchemeIs(url::kDataScheme));
+ DCHECK(frame->GetDocument().GetSecurityOrigin().ToString() == "null" || !url.SchemeIs(url::kDataScheme));
}
void ContentSettingsObserverQt::OnDestruct()
@@ -120,10 +116,8 @@ bool ContentSettingsObserverQt::AllowDatabase()
return false;
bool result = false;
- Send(new QtWebEngineHostMsg_AllowDatabase(
- routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(),
- url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(),
- &result));
+ Send(new QtWebEngineHostMsg_AllowDatabase(routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(),
+ url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), &result));
return result;
}
@@ -140,10 +134,9 @@ void ContentSettingsObserverQt::RequestFileSystemAccessAsync(base::OnceCallback<
// Verify there are no duplicate insertions.
DCHECK(inserted);
- Send(new QtWebEngineHostMsg_RequestFileSystemAccessAsync(
- routing_id(), m_currentRequestId,
- url::Origin(frame->GetSecurityOrigin()).GetURL(),
- url::Origin(frame->Top()->GetSecurityOrigin()).GetURL()));
+ Send(new QtWebEngineHostMsg_RequestFileSystemAccessAsync(routing_id(), m_currentRequestId,
+ url::Origin(frame->GetSecurityOrigin()).GetURL(),
+ url::Origin(frame->Top()->GetSecurityOrigin()).GetURL()));
}
bool ContentSettingsObserverQt::AllowIndexedDB(const WebSecurityOrigin &origin)
@@ -153,10 +146,8 @@ bool ContentSettingsObserverQt::AllowIndexedDB(const WebSecurityOrigin &origin)
return false;
bool result = false;
- Send(new QtWebEngineHostMsg_AllowIndexedDB(
- routing_id(), url::Origin(origin).GetURL(),
- url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(),
- &result));
+ Send(new QtWebEngineHostMsg_AllowIndexedDB(routing_id(), url::Origin(origin).GetURL(),
+ url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), &result));
return result;
}
@@ -172,9 +163,8 @@ bool ContentSettingsObserverQt::AllowStorage(bool local)
return permissions->second;
bool result = false;
- Send(new QtWebEngineHostMsg_AllowDOMStorage(
- routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(),
- url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), local, &result));
+ Send(new QtWebEngineHostMsg_AllowDOMStorage(routing_id(), url::Origin(frame->GetSecurityOrigin()).GetURL(),
+ url::Origin(frame->Top()->GetSecurityOrigin()).GetURL(), local, &result));
m_cachedStoragePermissions[key] = result;
return result;
}
diff --git a/src/core/renderer/content_settings_observer_qt.h b/src/core/renderer/content_settings_observer_qt.h
index 9c071aa3c..71e1fbca5 100644
--- a/src/core/renderer/content_settings_observer_qt.h
+++ b/src/core/renderer/content_settings_observer_qt.h
@@ -58,9 +58,9 @@ namespace QtWebEngineCore {
// Handles blocking content per content settings for each RenderFrame.
class ContentSettingsObserverQt
- : public content::RenderFrameObserver
- , public content::RenderFrameObserverTracker<ContentSettingsObserverQt>
- , public blink::WebContentSettingsClient
+ : public content::RenderFrameObserver
+ , public content::RenderFrameObserverTracker<ContentSettingsObserverQt>
+ , public blink::WebContentSettingsClient
{
public:
ContentSettingsObserverQt(content::RenderFrame *render_frame);
@@ -73,11 +73,9 @@ public:
bool AllowStorage(bool local) override;
private:
-
// RenderFrameObserver implementation:
bool OnMessageReceived(const IPC::Message &message) override;
- void DidCommitProvisionalLoad(bool is_same_document_navigation,
- ui::PageTransition transition) override;
+ void DidCommitProvisionalLoad(bool is_same_document_navigation, ui::PageTransition transition) override;
void OnDestruct() override;
// Message handlers.
@@ -98,4 +96,4 @@ private:
} // namespace QtWebEngineCore
-#endif // RENDERER_CONTENT_SETTINGS_OBSERVER_QT_H
+#endif // RENDERER_CONTENT_SETTINGS_OBSERVER_QT_H
diff --git a/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp
new file mode 100644
index 000000000..b43d9a24b
--- /dev/null
+++ b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.cpp
@@ -0,0 +1,103 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the QtWebEngine module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or (at your option) the GNU General
+** Public license version 3 or any later version approved by the KDE Free
+** Qt Foundation. The licenses are as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-2.0.html and
+** https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+// Copyright 2015 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 file.
+
+#include "loadable_plugin_placeholder_qt.h"
+#include "qtwebenginecoreglobal_p.h"
+
+#include "content/public/renderer/render_frame.h"
+#include "components/strings/grit/components_strings.h"
+#include "chrome/grit/renderer_resources.h"
+#include "gin/handle.h"
+#include "gin/wrappable.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/base/webui/jstemplate_builder.h"
+
+namespace QtWebEngineCore {
+
+// static
+gin::WrapperInfo LoadablePluginPlaceholderQt::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+LoadablePluginPlaceholderQt::LoadablePluginPlaceholderQt(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ const std::string& html_data,
+ const base::string16& title)
+ : plugins::LoadablePluginPlaceholder(render_frame, params, html_data)
+ , context_menu_request_id_(0)
+{}
+
+LoadablePluginPlaceholderQt::~LoadablePluginPlaceholderQt()
+{
+ if (context_menu_request_id_ && render_frame())
+ render_frame()->CancelContextMenu(context_menu_request_id_);
+}
+
+// TODO(bauerb): Move this method to NonLoadablePluginPlaceholder?
+// static
+LoadablePluginPlaceholderQt* LoadablePluginPlaceholderQt::CreateLoadableMissingPlugin(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params)
+{
+ const base::StringPiece template_html(ui::ResourceBundle::GetSharedInstance().GetRawDataResource(IDR_BLOCKED_PLUGIN_HTML));
+
+ base::DictionaryValue values;
+ values.SetString("name", "");
+ values.SetString("message", l10n_util::GetStringUTF8(IDS_PLUGIN_NOT_SUPPORTED));
+
+ const std::string html_data = webui::GetI18nTemplateHtml(template_html, &values);
+
+ // Will destroy itself when its WebViewPlugin is going away.
+ return new LoadablePluginPlaceholderQt(render_frame, params, html_data, params.mime_type.Utf16());
+}
+
+blink::WebPlugin* LoadablePluginPlaceholderQt::CreatePlugin()
+{
+ QT_NOT_YET_IMPLEMENTED
+ return nullptr;
+}
+
+v8::Local<v8::Value> LoadablePluginPlaceholderQt::GetV8Handle(v8::Isolate* isolate)
+{
+ return gin::CreateHandle(isolate, this).ToV8();
+}
+
+} // namespace QtWebEngineCore
diff --git a/src/core/net/custom_protocol_handler.h b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.h
index 625afc1d5..7bcad2d96 100644
--- a/src/core/net/custom_protocol_handler.h
+++ b/src/core/renderer/plugins/loadable_plugin_placeholder_qt.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -37,53 +37,48 @@
**
****************************************************************************/
-//
-// 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.
-//
+// Copyright 2015 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 file.
-#ifndef CUSTOM_PROTOCOL_HANDLER_H_
-#define CUSTOM_PROTOCOL_HANDLER_H_
+#ifndef LOADALBLE_PLUGIN_PLACEHOLDER_QT_H
+#define LOADALBLE_PLUGIN_PLACEHOLDER_QT_H
-#include "qtwebenginecoreglobal_p.h"
-#include "net/url_request/url_request_job_factory.h"
-
-#include <QtCore/QByteArray>
-#include <QtCore/QObject>
-#include <QtCore/QPointer>
-
-QT_FORWARD_DECLARE_CLASS(QIODevice)
-
-namespace net {
-class NetworkDelegate;
-class URLRequestJob;
-} // namespace
+#include "base/macros.h"
+#include "components/plugins/renderer/loadable_plugin_placeholder.h"
namespace QtWebEngineCore {
-class ProfileAdapter;
-
-// Implements a ProtocolHandler for custom URL schemes.
-// If |network_delegate_| is NULL then all file requests will fail with ERR_ACCESS_DENIED.
-class Q_WEBENGINECORE_PRIVATE_EXPORT CustomProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler
+class LoadablePluginPlaceholderQt final : public plugins::LoadablePluginPlaceholder
+ , public gin::Wrappable<LoadablePluginPlaceholderQt>
{
-
public:
- CustomProtocolHandler(QPointer<ProfileAdapter> profileAdapter);
+ static gin::WrapperInfo kWrapperInfo;
- net::URLRequestJob *MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const override;
+ // Creates a new WebViewPlugin with a MissingPlugin as a delegate.
+ static LoadablePluginPlaceholderQt* CreateLoadableMissingPlugin(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params);
private:
- DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
- QPointer<ProfileAdapter> m_profileAdapter;
+ LoadablePluginPlaceholderQt(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ const std::string& html_data,
+ const base::string16& title);
+ ~LoadablePluginPlaceholderQt() override;
+
+ // 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;
+
+ int context_menu_request_id_; // Nonzero when request pending.
+
+ DISALLOW_COPY_AND_ASSIGN(LoadablePluginPlaceholderQt);
};
-} // namespace
+} // namespace QtWebEngineCore
-#endif // CUSTOM_PROTOCOL_HANDLER_H_
+#endif // LOADALBLE_PLUGIN_PLACEHOLDER_QT_H
diff --git a/src/core/net/custom_protocol_handler.cpp b/src/core/renderer/plugins/plugin_placeholder_qt.cpp
index 7e8ee47ab..a72c29873 100644
--- a/src/core/net/custom_protocol_handler.cpp
+++ b/src/core/renderer/plugins/plugin_placeholder_qt.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -37,26 +37,39 @@
**
****************************************************************************/
-#include "custom_protocol_handler.h"
-#include "url_request_custom_job.h"
+// Copyright 2013 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 file.
-#include "net/base/net_errors.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_error_job.h"
+#include "plugin_placeholder_qt.h"
+
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/v8_value_converter.h"
+#include "gin/object_template_builder.h"
namespace QtWebEngineCore {
-CustomProtocolHandler::CustomProtocolHandler(QPointer<ProfileAdapter> profileAdapter)
- : m_profileAdapter(profileAdapter)
+// static
+gin::WrapperInfo PluginPlaceholderQt::kWrapperInfo = {gin::kEmbedderNativeGin};
+
+PluginPlaceholderQt::PluginPlaceholderQt(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ const std::string& html_data)
+ : PluginPlaceholderBase(render_frame, params, html_data)
+{}
+
+PluginPlaceholderQt::~PluginPlaceholderQt() {}
+
+v8::Local<v8::Value> PluginPlaceholderQt::GetV8Handle(v8::Isolate* isolate)
{
+ return gin::CreateHandle(isolate, this).ToV8();
}
-net::URLRequestJob *CustomProtocolHandler::MaybeCreateJob(net::URLRequest *request, net::NetworkDelegate *networkDelegate) const
+gin::ObjectTemplateBuilder PluginPlaceholderQt::GetObjectTemplateBuilder(v8::Isolate* isolate)
{
- if (!networkDelegate)
- return new net::URLRequestErrorJob(request, nullptr, net::ERR_ACCESS_DENIED);
-
- return new URLRequestCustomJob(request, networkDelegate, request->url().scheme(), m_profileAdapter);
+ return gin::Wrappable<PluginPlaceholderQt>::GetObjectTemplateBuilder(isolate)
+ .SetMethod<void (QtWebEngineCore::PluginPlaceholderQt::*)()>(
+ "hide", &PluginPlaceholderQt::HideCallback);
}
-} // namespace
+} // namespace QtWebEngineCore
diff --git a/src/core/net/url_request_context_getter_qt.cpp b/src/core/renderer/plugins/plugin_placeholder_qt.h
index 6081a5e9f..a99c0d045 100644
--- a/src/core/net/url_request_context_getter_qt.cpp
+++ b/src/core/renderer/plugins/plugin_placeholder_qt.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtWebEngine module of the Qt Toolkit.
@@ -37,33 +37,42 @@
**
****************************************************************************/
-#include "url_request_context_getter_qt.h"
-#include "profile_io_data_qt.h"
+// Copyright 2013 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 file.
-#include "base/task/post_task.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
+#ifndef PLUGIN_PLACEHOLDER_QT_H
+#define PLUGIN_PLACEHOLDER_QT_H
+
+#include "base/macros.h"
+#include "components/plugins/renderer/plugin_placeholder.h"
+#include "gin/handle.h"
+#include "gin/wrappable.h"
+#include "third_party/blink/public/web/web_plugin_params.h"
namespace QtWebEngineCore {
-URLRequestContextGetterQt::URLRequestContextGetterQt(ProfileIODataQt *data)
- : m_profileIOData(data)
+// A basic placeholder that supports only hiding.
+class PluginPlaceholderQt final : public plugins::PluginPlaceholderBase
+ , public gin::Wrappable<PluginPlaceholderQt>
{
-}
+public:
+ static gin::WrapperInfo kWrapperInfo;
-URLRequestContextGetterQt::~URLRequestContextGetterQt()
-{
-}
+ PluginPlaceholderQt(content::RenderFrame* render_frame,
+ const blink::WebPluginParams& params,
+ const std::string& html_data);
+ ~PluginPlaceholderQt() override;
-net::URLRequestContext *URLRequestContextGetterQt::GetURLRequestContext()
-{
- Q_ASSERT(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
- return m_profileIOData->urlRequestContext();
-}
+private:
+ // WebViewPlugin::Delegate methods:
+ v8::Local<v8::Value> GetV8Handle(v8::Isolate* isolate) final;
-scoped_refptr<base::SingleThreadTaskRunner> URLRequestContextGetterQt::GetNetworkTaskRunner() const
-{
- return base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO});
-}
+ // gin::Wrappable method:
+ gin::ObjectTemplateBuilder GetObjectTemplateBuilder(
+ v8::Isolate* isolate) override;
+};
+
+} // namespace QtWebEngineCore
-} // namespace QtWebEngineCore
+#endif // PLUGIN_PLACEHOLDER_QT_H
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 67cdd6b66..b85ff7249 100644
--- a/src/core/renderer/print_web_view_helper_delegate_qt.cpp
+++ b/src/core/renderer/print_web_view_helper_delegate_qt.cpp
@@ -52,21 +52,17 @@
#include "web_engine_library_info.h"
namespace QtWebEngineCore {
-PrintWebViewHelperDelegateQt::~PrintWebViewHelperDelegateQt()
-{
-
-}
+PrintWebViewHelperDelegateQt::~PrintWebViewHelperDelegateQt() {}
bool PrintWebViewHelperDelegateQt::CancelPrerender(content::RenderFrame *)
{
return false;
}
-blink::WebElement PrintWebViewHelperDelegateQt::GetPdfElement(blink::WebLocalFrame* frame)
+blink::WebElement PrintWebViewHelperDelegateQt::GetPdfElement(blink::WebLocalFrame *frame)
{
GURL url = frame->GetDocument().Url();
- if (url.SchemeIs(extensions::kExtensionScheme) && url.host() == extension_misc::kPdfExtensionId)
- {
+ if (url.SchemeIs(extensions::kExtensionScheme) && url.host() == extension_misc::kPdfExtensionId) {
// <object> with id="plugin" is created in
// chrome/browser/resources/pdf/pdf.js.
auto plugin_element = frame->GetDocument().GetElementById("plugin");
@@ -81,7 +77,7 @@ bool PrintWebViewHelperDelegateQt::IsPrintPreviewEnabled()
return true;
}
-bool PrintWebViewHelperDelegateQt::OverridePrint(blink::WebLocalFrame* frame)
+bool PrintWebViewHelperDelegateQt::OverridePrint(blink::WebLocalFrame *frame)
{
return false;
}
diff --git a/src/core/renderer/print_web_view_helper_delegate_qt.h b/src/core/renderer/print_web_view_helper_delegate_qt.h
index e3020922f..f02580b91 100644
--- a/src/core/renderer/print_web_view_helper_delegate_qt.h
+++ b/src/core/renderer/print_web_view_helper_delegate_qt.h
@@ -57,15 +57,14 @@ class PrintWebViewHelperDelegateQt : public printing::PrintRenderFrameHelper::De
public:
~PrintWebViewHelperDelegateQt() override;
- bool CancelPrerender(content::RenderFrame* render_frame) override;
+ bool CancelPrerender(content::RenderFrame *render_frame) override;
- blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) override;
+ blink::WebElement GetPdfElement(blink::WebLocalFrame *frame) override;
bool IsPrintPreviewEnabled() override;
- bool OverridePrint(blink::WebLocalFrame* frame) override;
-}; // class PrintWebViewHelperDelegateQt
+ bool OverridePrint(blink::WebLocalFrame *frame) override;
+}; // class PrintWebViewHelperDelegateQt
}
#endif // PRINT_WEB_VIEW_HELPER_DELEGATE_QT_H
-
diff --git a/src/core/renderer/render_frame_observer_qt.cpp b/src/core/renderer/render_frame_observer_qt.cpp
index c48ef3b5c..cc01acec6 100644
--- a/src/core/renderer/render_frame_observer_qt.cpp
+++ b/src/core/renderer/render_frame_observer_qt.cpp
@@ -55,30 +55,25 @@
namespace QtWebEngineCore {
-RenderFrameObserverQt::RenderFrameObserverQt(content::RenderFrame* render_frame,
- web_cache::WebCacheImpl* web_cache_impl)
+RenderFrameObserverQt::RenderFrameObserverQt(content::RenderFrame *render_frame, web_cache::WebCacheImpl *web_cache_impl)
: RenderFrameObserver(render_frame)
, RenderFrameObserverTracker<RenderFrameObserverQt>(render_frame)
, m_isFrameDetached(false)
, m_web_cache_impl(web_cache_impl)
-{
-}
+{}
-RenderFrameObserverQt::~RenderFrameObserverQt()
-{
-}
+RenderFrameObserverQt::~RenderFrameObserverQt() {}
-void RenderFrameObserverQt::OnDestruct() {
+void RenderFrameObserverQt::OnDestruct()
+{
delete this;
}
#if QT_CONFIG(webengine_pepper_plugins)
-void RenderFrameObserverQt::DidCreatePepperPlugin(content::RendererPpapiHost* host)
+void RenderFrameObserverQt::DidCreatePepperPlugin(content::RendererPpapiHost *host)
{
- host->GetPpapiHost()->AddHostFactoryFilter(
- base::WrapUnique(new PepperRendererHostFactoryQt(host)));
- host->GetPpapiHost()->AddInstanceMessageFilter(
- base::WrapUnique(new PepperSharedMemoryMessageFilter(host)));
+ host->GetPpapiHost()->AddHostFactoryFilter(base::WrapUnique(new PepperRendererHostFactoryQt(host)));
+ host->GetPpapiHost()->AddInstanceMessageFilter(base::WrapUnique(new PepperSharedMemoryMessageFilter(host)));
}
#endif
diff --git a/src/core/renderer/render_frame_observer_qt.h b/src/core/renderer/render_frame_observer_qt.h
index fb9fd3869..6bdf4ad23 100644
--- a/src/core/renderer/render_frame_observer_qt.h
+++ b/src/core/renderer/render_frame_observer_qt.h
@@ -57,23 +57,22 @@ class WebCacheImpl;
namespace QtWebEngineCore {
class RenderFrameObserverQt
- : public content::RenderFrameObserver
- , public content::RenderFrameObserverTracker<RenderFrameObserverQt>
+ : public content::RenderFrameObserver
+ , public content::RenderFrameObserverTracker<RenderFrameObserverQt>
{
public:
- explicit RenderFrameObserverQt(content::RenderFrame* render_frame,
- web_cache::WebCacheImpl* web_cache_impl);
+ explicit RenderFrameObserverQt(content::RenderFrame *render_frame, web_cache::WebCacheImpl *web_cache_impl);
~RenderFrameObserverQt();
#if QT_CONFIG(webengine_pepper_plugins)
- void DidCreatePepperPlugin(content::RendererPpapiHost* host) override;
+ void DidCreatePepperPlugin(content::RendererPpapiHost *host) override;
#endif
void OnDestruct() override;
void FrameDetached() override;
bool isFrameDetached() const;
- service_manager::BinderRegistry* registry() { return &registry_; }
+ service_manager::BinderRegistry *registry() { return &registry_; }
private:
DISALLOW_COPY_AND_ASSIGN(RenderFrameObserverQt);
diff --git a/src/core/renderer/render_thread_observer_qt.cpp b/src/core/renderer/render_thread_observer_qt.cpp
index 64b9fd961..4912ebfc2 100644
--- a/src/core/renderer/render_thread_observer_qt.cpp
+++ b/src/core/renderer/render_thread_observer_qt.cpp
@@ -52,7 +52,8 @@ bool RenderThreadObserverQt::m_isIncognitoProcess = false;
void RenderThreadObserverQt::RegisterMojoInterfaces(blink::AssociatedInterfaceRegistry *associated_interfaces)
{
- associated_interfaces->AddInterface(base::Bind(&RenderThreadObserverQt::OnRendererConfigurationAssociatedRequest, base::Unretained(this)));
+ associated_interfaces->AddInterface(
+ base::Bind(&RenderThreadObserverQt::OnRendererConfigurationAssociatedRequest, base::Unretained(this)));
}
void RenderThreadObserverQt::UnregisterMojoInterfaces(blink::AssociatedInterfaceRegistry *associated_interfaces)
@@ -65,9 +66,10 @@ void RenderThreadObserverQt::SetInitialConfiguration(bool is_incognito_process)
m_isIncognitoProcess = is_incognito_process;
}
-void RenderThreadObserverQt::OnRendererConfigurationAssociatedRequest(qtwebengine::mojom::RendererConfigurationAssociatedRequest request)
+void RenderThreadObserverQt::OnRendererConfigurationAssociatedRequest(
+ mojo::PendingAssociatedReceiver<qtwebengine::mojom::RendererConfiguration> receiver)
{
- m_rendererConfigurationBindings.AddBinding(this, std::move(request));
+ m_rendererConfigurationReceivers.Add(this, std::move(receiver));
}
} // namespace
diff --git a/src/core/renderer/render_thread_observer_qt.h b/src/core/renderer/render_thread_observer_qt.h
index 29b842ab4..05372049b 100644
--- a/src/core/renderer/render_thread_observer_qt.h
+++ b/src/core/renderer/render_thread_observer_qt.h
@@ -41,15 +41,17 @@
#define RENDER_THREAD_OBSERVER_QT_H
#include "content/public/renderer/render_thread_observer.h"
-#include "mojo/public/cpp/bindings/associated_binding_set.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "qtwebengine/common/renderer_configuration.mojom.h"
namespace QtWebEngineCore {
-class RenderThreadObserverQt : public content::RenderThreadObserver,
- public qtwebengine::mojom::RendererConfiguration {
+class RenderThreadObserverQt
+ : public content::RenderThreadObserver
+ , public qtwebengine::mojom::RendererConfiguration
+{
public:
-
RenderThreadObserverQt() = default;
~RenderThreadObserverQt() override = default;
@@ -63,11 +65,12 @@ private:
// qtwebengine::mojom::RendererConfiguration:
void SetInitialConfiguration(bool is_incognito_process) override;
- void OnRendererConfigurationAssociatedRequest(qtwebengine::mojom::RendererConfigurationAssociatedRequest request);
+ void OnRendererConfigurationAssociatedRequest(
+ mojo::PendingAssociatedReceiver<qtwebengine::mojom::RendererConfiguration> receiver);
static bool m_isIncognitoProcess;
- mojo::AssociatedBindingSet<qtwebengine::mojom::RendererConfiguration> m_rendererConfigurationBindings;
+ mojo::AssociatedReceiverSet<qtwebengine::mojom::RendererConfiguration> m_rendererConfigurationReceivers;
DISALLOW_COPY_AND_ASSIGN(RenderThreadObserverQt);
};
diff --git a/src/core/renderer/render_view_observer_qt.cpp b/src/core/renderer/render_view_observer_qt.cpp
index 7e7c7bdf8..731d8b97d 100644
--- a/src/core/renderer/render_view_observer_qt.cpp
+++ b/src/core/renderer/render_view_observer_qt.cpp
@@ -50,18 +50,15 @@
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_view.h"
-RenderViewObserverQt::RenderViewObserverQt(
- content::RenderView* render_view)
- : content::RenderViewObserver(render_view)
-{
-}
+RenderViewObserverQt::RenderViewObserverQt(content::RenderView *render_view) : content::RenderViewObserver(render_view)
+{}
void RenderViewObserverQt::onFetchDocumentMarkup(quint64 requestId)
{
blink::WebString markup;
if (render_view()->GetWebView()->MainFrame()->IsWebLocalFrame())
markup = blink::WebFrameContentDumper::DumpAsMarkup(
- static_cast<blink::WebLocalFrame*>(render_view()->GetWebView()->MainFrame()));
+ static_cast<blink::WebLocalFrame *>(render_view()->GetWebView()->MainFrame()));
Send(new RenderViewObserverHostQt_DidFetchDocumentMarkup(routing_id(), requestId, markup.Utf16()));
}
@@ -69,9 +66,8 @@ void RenderViewObserverQt::onFetchDocumentInnerText(quint64 requestId)
{
blink::WebString text;
if (render_view()->GetWebView()->MainFrame()->IsWebLocalFrame())
- text = blink::WebFrameContentDumper::DumpWebViewAsText(
- render_view()->GetWebView(),
- std::numeric_limits<std::size_t>::max());
+ text = blink::WebFrameContentDumper::DumpWebViewAsText(render_view()->GetWebView(),
+ std::numeric_limits<std::size_t>::max());
Send(new RenderViewObserverHostQt_DidFetchDocumentInnerText(routing_id(), requestId, text.Utf16()));
}
@@ -85,7 +81,7 @@ void RenderViewObserverQt::OnDestruct()
delete this;
}
-bool RenderViewObserverQt::OnMessageReceived(const IPC::Message& message)
+bool RenderViewObserverQt::OnMessageReceived(const IPC::Message &message)
{
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderViewObserverQt, message)
diff --git a/src/core/renderer/render_view_observer_qt.h b/src/core/renderer/render_view_observer_qt.h
index a878eebe8..5c555b222 100644
--- a/src/core/renderer/render_view_observer_qt.h
+++ b/src/core/renderer/render_view_observer_qt.h
@@ -43,9 +43,10 @@
#include <QtGlobal>
-class RenderViewObserverQt : public content::RenderViewObserver {
+class RenderViewObserverQt : public content::RenderViewObserver
+{
public:
- RenderViewObserverQt(content::RenderView* render_view);
+ RenderViewObserverQt(content::RenderView *render_view);
private:
void onFetchDocumentMarkup(quint64 requestId);
@@ -54,7 +55,7 @@ private:
void OnDestruct() override;
- bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message &message) override;
DISALLOW_COPY_AND_ASSIGN(RenderViewObserverQt);
};
diff --git a/src/core/renderer/user_resource_controller.cpp b/src/core/renderer/user_resource_controller.cpp
index 2613d262e..5c1bd301f 100644
--- a/src/core/renderer/user_resource_controller.cpp
+++ b/src/core/renderer/user_resource_controller.cpp
@@ -64,7 +64,7 @@
Q_GLOBAL_STATIC(UserResourceController, qt_webengine_userResourceController)
-static content::RenderView * const globalScriptsIndex = 0;
+static content::RenderView *const globalScriptsIndex = nullptr;
// Scripts meant to run after the load event will be run 500ms after DOMContentLoaded if the load event doesn't come within that delay.
static const int afterLoadTimeout = 500;
@@ -74,7 +74,8 @@ static int validUserScriptSchemes()
return URLPattern::SCHEME_HTTP | URLPattern::SCHEME_HTTPS | URLPattern::SCHEME_FILE | URLPattern::SCHEME_QRC;
}
-static bool regexMatchesURL(const std::string &pat, const GURL &url) {
+static bool regexMatchesURL(const std::string &pat, const GURL &url)
+{
QRegularExpression qre(QtWebEngineCore::toQt(pat));
qre.setPatternOptions(QRegularExpression::CaseInsensitiveOption);
if (!qre.isValid())
@@ -96,7 +97,8 @@ static bool includeRuleMatchesURL(const std::string &pat, const GURL &url)
return false;
}
-static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url) {
+static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url)
+{
// Logic taken from Chromium (extensions/common/user_script.cc)
bool matchFound;
if (!scriptData.urlPatterns.empty()) {
@@ -133,7 +135,7 @@ static bool scriptMatchesURL(const UserScriptData &scriptData, const GURL &url)
class UserResourceController::RenderFrameObserverHelper : public content::RenderFrameObserver
{
public:
- RenderFrameObserverHelper(content::RenderFrame* render_frame);
+ RenderFrameObserverHelper(content::RenderFrame *render_frame);
private:
// RenderFrameObserver implementation.
@@ -142,7 +144,7 @@ private:
void DidFinishLoad() override;
void FrameDetached() override;
void OnDestruct() override;
- bool OnMessageReceived(const IPC::Message& message) override;
+ bool OnMessageReceived(const IPC::Message &message) override;
void onUserScriptAdded(const UserScriptData &);
void onUserScriptRemoved(const UserScriptData &);
@@ -154,12 +156,10 @@ private:
// Helper class to create WeakPtrs so the AfterLoad tasks can be canceled and to
// avoid running scripts more than once per injection point.
-class UserResourceController::RenderFrameObserverHelper::Runner : public base::SupportsWeakPtr<Runner> {
+class UserResourceController::RenderFrameObserverHelper::Runner : public base::SupportsWeakPtr<Runner>
+{
public:
- explicit Runner(blink::WebLocalFrame *frame)
- : m_frame(frame)
- {
- }
+ explicit Runner(blink::WebLocalFrame *frame) : m_frame(frame) {}
void run(UserScriptData::InjectionPoint p)
{
@@ -179,7 +179,8 @@ private:
class UserResourceController::RenderViewObserverHelper : public content::RenderViewObserver
{
public:
- RenderViewObserverHelper(content::RenderView* render_view);
+ RenderViewObserverHelper(content::RenderView *render_view);
+
private:
// RenderViewObserver implementation.
void OnDestruct() override;
@@ -201,8 +202,7 @@ void UserResourceController::runScripts(UserScriptData::InjectionPoint p, blink:
for (uint64_t id : qAsConst(scriptsToRun)) {
const UserScriptData &script = m_scripts.value(id);
- if (script.injectionPoint != p
- || (!script.injectForSubframes && !isMainFrame))
+ if (script.injectionPoint != p || (!script.injectForSubframes && !isMainFrame))
continue;
if (!scriptMatchesURL(script, frame->GetDocument().Url()))
continue;
@@ -221,13 +221,11 @@ void UserResourceController::RunScriptsAtDocumentEnd(content::RenderFrame *rende
UserResourceController::RenderFrameObserverHelper::RenderFrameObserverHelper(content::RenderFrame *render_frame)
: content::RenderFrameObserver(render_frame)
-{
-}
+{}
UserResourceController::RenderViewObserverHelper::RenderViewObserverHelper(content::RenderView *render_view)
: content::RenderViewObserver(render_view)
-{
-}
+{}
void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad(bool is_same_document_navigation,
ui::PageTransition /*transitionbool*/)
@@ -242,8 +240,7 @@ void UserResourceController::RenderFrameObserverHelper::DidCommitProvisionalLoad
m_runner.reset(new Runner(render_frame()->GetWebFrame()));
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::DocumentElementCreation));
+ FROM_HERE, base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::DocumentElementCreation));
}
void UserResourceController::RenderFrameObserverHelper::DidFinishDocumentLoad()
@@ -252,18 +249,15 @@ void UserResourceController::RenderFrameObserverHelper::DidFinishDocumentLoad()
// called instead of DidCommitProvisionalLoad).
if (m_runner)
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
- FROM_HERE,
- base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::AfterLoad),
- base::TimeDelta::FromMilliseconds(afterLoadTimeout));
-
+ FROM_HERE, base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::AfterLoad),
+ base::TimeDelta::FromMilliseconds(afterLoadTimeout));
}
void UserResourceController::RenderFrameObserverHelper::DidFinishLoad()
{
if (m_runner)
base::ThreadTaskRunnerHandle::Get()->PostTask(
- FROM_HERE,
- base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::AfterLoad));
+ FROM_HERE, base::BindOnce(&Runner::run, m_runner->AsWeakPtr(), UserScriptData::AfterLoad));
}
void UserResourceController::RenderFrameObserverHelper::FrameDetached()
@@ -293,7 +287,7 @@ bool UserResourceController::RenderFrameObserverHelper::OnMessageReceived(const
IPC_MESSAGE_HANDLER(RenderFrameObserverHelper_ClearScripts, onScriptsCleared)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
- return handled;
+ return handled;
}
void UserResourceController::RenderFrameObserverHelper::onUserScriptAdded(const UserScriptData &script)
@@ -411,4 +405,3 @@ void UserResourceController::onClearScripts()
{
clearScriptsForView(globalScriptsIndex);
}
-
diff --git a/src/core/renderer/user_resource_controller.h b/src/core/renderer/user_resource_controller.h
index 0b5e0a0c6..3a493b9b7 100644
--- a/src/core/renderer/user_resource_controller.h
+++ b/src/core/renderer/user_resource_controller.h
@@ -56,7 +56,8 @@ class RenderFrame;
class RenderView;
}
-class UserResourceController : public content::RenderThreadObserver {
+class UserResourceController : public content::RenderThreadObserver
+{
public:
static UserResourceController *instance();
diff --git a/src/core/renderer/web_channel_ipc_transport.cpp b/src/core/renderer/web_channel_ipc_transport.cpp
index 108686068..1fb3bc678 100644
--- a/src/core/renderer/web_channel_ipc_transport.cpp
+++ b/src/core/renderer/web_channel_ipc_transport.cpp
@@ -61,11 +61,13 @@
namespace QtWebEngineCore {
-class WebChannelTransport : public gin::Wrappable<WebChannelTransport> {
+class WebChannelTransport : public gin::Wrappable<WebChannelTransport>
+{
public:
static gin::WrapperInfo kWrapperInfo;
static void Install(blink::WebLocalFrame *frame, uint worldId);
static void Uninstall(blink::WebLocalFrame *frame, uint worldId);
+
private:
WebChannelTransport() {}
void NativeQtSendMessage(gin::Arguments *args);
@@ -152,9 +154,7 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args)
v8::Local<v8::String> jsonString = v8::Local<v8::String>::Cast(jsonValue);
QByteArray json(jsonString->Utf8Length(isolate), 0);
- jsonString->WriteUtf8(isolate,
- json.data(), json.size(),
- nullptr, v8::String::REPLACE_INVALID_UTF8);
+ jsonString->WriteUtf8(isolate, json.data(), json.size(), nullptr, v8::String::REPLACE_INVALID_UTF8);
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(json, &error);
@@ -165,30 +165,28 @@ void WebChannelTransport::NativeQtSendMessage(gin::Arguments *args)
int size = 0;
const char *rawData = doc.rawData(&size);
- qtwebchannel::mojom::WebChannelTransportHostAssociatedPtr webChannelTransport;
+ mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportHost> webChannelTransport;
renderFrame->GetRemoteAssociatedInterfaces()->GetInterface(&webChannelTransport);
webChannelTransport->DispatchWebChannelMessage(std::vector<uint8_t>(rawData, rawData + size));
}
gin::ObjectTemplateBuilder WebChannelTransport::GetObjectTemplateBuilder(v8::Isolate *isolate)
{
- return gin::Wrappable<WebChannelTransport>::GetObjectTemplateBuilder(isolate)
- .SetMethod("send", &WebChannelTransport::NativeQtSendMessage);
+ return gin::Wrappable<WebChannelTransport>::GetObjectTemplateBuilder(isolate).SetMethod(
+ "send", &WebChannelTransport::NativeQtSendMessage);
}
WebChannelIPCTransport::WebChannelIPCTransport(content::RenderFrame *renderFrame)
- : content::RenderFrameObserver(renderFrame)
- , m_worldId(0)
- , m_worldInitialized(false)
+ : content::RenderFrameObserver(renderFrame), m_worldId(0), m_worldInitialized(false)
{
renderFrame->GetAssociatedInterfaceRegistry()->AddInterface(
- base::Bind(&WebChannelIPCTransport::BindRequest, base::Unretained(this)));
+ base::BindRepeating(&WebChannelIPCTransport::BindReceiver, base::Unretained(this)));
}
-void WebChannelIPCTransport::BindRequest(
- qtwebchannel::mojom::WebChannelTransportRenderAssociatedRequest request) {
-
- m_binding.AddBinding(this, std::move(request));
+void WebChannelIPCTransport::BindReceiver(
+ mojo::PendingAssociatedReceiver<qtwebchannel::mojom::WebChannelTransportRender> receiver)
+{
+ m_receivers.Add(this, std::move(receiver));
}
void WebChannelIPCTransport::SetWorldId(uint32_t worldId)
@@ -208,7 +206,7 @@ void WebChannelIPCTransport::SetWorldId(uint32_t worldId)
void WebChannelIPCTransport::ResetWorldId()
{
- if (m_worldInitialized && m_canUseContext)
+ if (m_worldInitialized && m_canUseContext)
WebChannelTransport::Uninstall(render_frame()->GetWebFrame(), m_worldId);
m_worldInitialized = false;
@@ -222,8 +220,8 @@ void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t
if (!m_canUseContext)
return;
- QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()),
- binaryJson.size(), QJsonDocument::BypassValidation);
+ QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()), binaryJson.size(),
+ QJsonDocument::BypassValidation);
DCHECK(doc.isObject());
QByteArray json = doc.toJson(QJsonDocument::Compact);
@@ -242,22 +240,23 @@ void WebChannelIPCTransport::DispatchWebChannelMessage(const std::vector<uint8_t
if (qtObjectValue.IsEmpty() || !qtObjectValue.ToLocalChecked()->IsObject())
return;
v8::Local<v8::Object> qtObject = v8::Local<v8::Object>::Cast(qtObjectValue.ToLocalChecked());
- v8::MaybeLocal<v8::Value> webChannelObjectValue(qtObject->Get(context, gin::StringToV8(isolate, "webChannelTransport")));
+ v8::MaybeLocal<v8::Value> webChannelObjectValue(
+ qtObject->Get(context, gin::StringToV8(isolate, "webChannelTransport")));
if (webChannelObjectValue.IsEmpty() || !webChannelObjectValue.ToLocalChecked()->IsObject())
return;
v8::Local<v8::Object> webChannelObject = v8::Local<v8::Object>::Cast(webChannelObjectValue.ToLocalChecked());
v8::MaybeLocal<v8::Value> callbackValue(webChannelObject->Get(context, gin::StringToV8(isolate, "onmessage")));
if (callbackValue.IsEmpty() || !callbackValue.ToLocalChecked()->IsFunction()) {
- LOG(WARNING) << "onmessage is not a callable property of qt.webChannelTransport. Some things might not work as expected.";
+ LOG(WARNING) << "onmessage is not a callable property of qt.webChannelTransport. Some things might not work as "
+ "expected.";
return;
}
v8::Local<v8::Object> messageObject(v8::Object::New(isolate));
v8::Maybe<bool> wasSet = messageObject->DefineOwnProperty(
- context,
- v8::String::NewFromUtf8(isolate, "data").ToLocalChecked(),
- v8::String::NewFromUtf8(isolate, json.constData(), v8::NewStringType::kNormal, json.size()).ToLocalChecked(),
- v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
+ context, v8::String::NewFromUtf8(isolate, "data").ToLocalChecked(),
+ v8::String::NewFromUtf8(isolate, json.constData(), v8::NewStringType::kNormal, json.size()).ToLocalChecked(),
+ v8::PropertyAttribute(v8::ReadOnly | v8::DontDelete));
DCHECK(!wasSet.IsNothing() && wasSet.FromJust());
v8::Local<v8::Function> callback = v8::Local<v8::Function>::Cast(callbackValue.ToLocalChecked());
diff --git a/src/core/renderer/web_channel_ipc_transport.h b/src/core/renderer/web_channel_ipc_transport.h
index 178c20ed1..15778a7bc 100644
--- a/src/core/renderer/web_channel_ipc_transport.h
+++ b/src/core/renderer/web_channel_ipc_transport.h
@@ -42,15 +42,18 @@
#include "content/public/renderer/render_frame_observer.h"
#include "services/service_manager/public/cpp/binder_registry.h"
-#include "mojo/public/cpp/bindings/associated_binding_set.h"
+#include "mojo/public/cpp/bindings/associated_receiver_set.h"
+#include "mojo/public/cpp/bindings/pending_associated_receiver.h"
#include "qtwebengine/browser/qtwebchannel.mojom.h"
#include <QtCore/qglobal.h>
namespace QtWebEngineCore {
-class WebChannelIPCTransport: private content::RenderFrameObserver,
- public qtwebchannel::mojom::WebChannelTransportRender {
+class WebChannelIPCTransport
+ : private content::RenderFrameObserver
+ , public qtwebchannel::mojom::WebChannelTransportRender
+{
public:
WebChannelIPCTransport(content::RenderFrame *);
@@ -58,13 +61,13 @@ private:
// qtwebchannel::mojom::WebChannelTransportRender
void SetWorldId(uint32_t worldId) override;
void ResetWorldId() override;
- void DispatchWebChannelMessage(const std::vector<uint8_t>& binaryJson, uint32_t worldId) override;
+ void DispatchWebChannelMessage(const std::vector<uint8_t> &binaryJson, uint32_t worldId) override;
// RenderFrameObserver
void WillReleaseScriptContext(v8::Local<v8::Context> context, int worldId) override;
void DidClearWindowObject() override;
void OnDestruct() override;
- void BindRequest(qtwebchannel::mojom::WebChannelTransportRenderAssociatedRequest request);
+ void BindReceiver(mojo::PendingAssociatedReceiver<qtwebchannel::mojom::WebChannelTransportRender> receiver);
private:
// The worldId from our WebChannelIPCTransportHost or empty when there is no
@@ -73,7 +76,7 @@ private:
bool m_worldInitialized;
// True means it's currently OK to manipulate the frame's script context.
bool m_canUseContext = false;
- mojo::AssociatedBindingSet<qtwebchannel::mojom::WebChannelTransportRender> m_binding;
+ mojo::AssociatedReceiverSet<qtwebchannel::mojom::WebChannelTransportRender> m_receivers;
};
} // namespace
diff --git a/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp b/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp
index 5d7c3973f..bd93f0dd3 100644
--- a/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp
+++ b/src/core/renderer_host/pepper/pepper_isolated_file_system_message_filter.cpp
@@ -85,7 +85,7 @@ scoped_refptr<base::TaskRunner> PepperIsolatedFileSystemMessageFilter::OverrideT
{
// In order to reach ExtensionSystem, we need to get ProfileManager first.
// ProfileManager lives in UI thread, so we need to do this in UI thread.
- return base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI});
+ return base::CreateSingleThreadTaskRunner({content::BrowserThread::UI});
}
int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived(const IPC::Message& msg, ppapi::host::HostMessageContext *context)
diff --git a/src/core/renderer_host/render_view_observer_host_qt.cpp b/src/core/renderer_host/render_view_observer_host_qt.cpp
index c097e102d..165a9d86a 100644
--- a/src/core/renderer_host/render_view_observer_host_qt.cpp
+++ b/src/core/renderer_host/render_view_observer_host_qt.cpp
@@ -69,7 +69,7 @@ void RenderViewObserverHostQt::fetchDocumentInnerText(quint64 requestId)
web_contents()->GetRenderViewHost()->GetRoutingID(), requestId));
}
-bool RenderViewObserverHostQt::OnMessageReceived(const IPC::Message& message)
+bool RenderViewObserverHostQt::OnMessageReceived(const IPC::Message &message)
{
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(RenderViewObserverHostQt, message)
@@ -80,15 +80,14 @@ bool RenderViewObserverHostQt::OnMessageReceived(const IPC::Message& message)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
-
}
-void RenderViewObserverHostQt::onDidFetchDocumentMarkup(quint64 requestId, const base::string16& markup)
+void RenderViewObserverHostQt::onDidFetchDocumentMarkup(quint64 requestId, const base::string16 &markup)
{
m_adapterClient->didFetchDocumentMarkup(requestId, toQt(markup));
}
-void RenderViewObserverHostQt::onDidFetchDocumentInnerText(quint64 requestId, const base::string16& innerText)
+void RenderViewObserverHostQt::onDidFetchDocumentInnerText(quint64 requestId, const base::string16 &innerText)
{
m_adapterClient->didFetchDocumentInnerText(requestId, toQt(innerText));
}
diff --git a/src/core/renderer_host/render_view_observer_host_qt.h b/src/core/renderer_host/render_view_observer_host_qt.h
index a08263e07..8590ecbc5 100644
--- a/src/core/renderer_host/render_view_observer_host_qt.h
+++ b/src/core/renderer_host/render_view_observer_host_qt.h
@@ -45,7 +45,7 @@
#include <QtGlobal>
namespace content {
- class WebContents;
+class WebContents;
}
namespace QtWebEngineCore {
@@ -55,14 +55,14 @@ class WebContentsAdapterClient;
class RenderViewObserverHostQt : public content::WebContentsObserver
{
public:
- RenderViewObserverHostQt(content::WebContents*, WebContentsAdapterClient *adapterClient);
+ RenderViewObserverHostQt(content::WebContents *, WebContentsAdapterClient *adapterClient);
void fetchDocumentMarkup(quint64 requestId);
void fetchDocumentInnerText(quint64 requestId);
private:
- bool OnMessageReceived(const IPC::Message& message) override;
- void onDidFetchDocumentMarkup(quint64 requestId, const base::string16& markup);
- void onDidFetchDocumentInnerText(quint64 requestId, const base::string16& innerText);
+ bool OnMessageReceived(const IPC::Message &message) override;
+ void onDidFetchDocumentMarkup(quint64 requestId, const base::string16 &markup);
+ void onDidFetchDocumentInnerText(quint64 requestId, const base::string16 &innerText);
WebContentsAdapterClient *m_adapterClient;
};
diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp
deleted file mode 100644
index a08e2cf88..000000000
--- a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.cpp
+++ /dev/null
@@ -1,186 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// Copyright 2013 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 "resource_dispatcher_host_delegate_qt.h"
-
-#include "base/bind.h"
-#include "base/guid.h"
-#include "base/strings/stringprintf.h"
-#include "base/task/post_task.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/download_manager.h"
-#include "content/public/browser/download_request_utils.h"
-#include "content/public/browser/navigation_controller.h"
-
-#include "content/public/browser/render_frame_host.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/resource_dispatcher_host.h"
-#include "content/public/browser/resource_request_info.h"
-#include "content/public/browser/stream_info.h"
-#include "content/public/browser/web_contents.h"
-
-#include "extensions/extension_system_qt.h"
-#include "extensions/browser/info_map.h"
-#include "extensions/common/constants.h"
-#include "extensions/common/extension.h"
-#include "extensions/common/manifest_handlers/mime_types_handler.h"
-
-#include "net/base/escape.h"
-#include "net/url_request/url_request.h"
-
-#include "profile_io_data_qt.h"
-#include "type_conversion.h"
-#include "web_contents_delegate_qt.h"
-#include "web_engine_settings.h"
-
-namespace QtWebEngineCore {
-
-void OnPdfStreamIntercepted(
- const GURL& original_url,
- std::string extension_id,
- int frame_tree_node_id,
- const content::ResourceRequestInfo::WebContentsGetter&
- web_contents_getter) {
- content::WebContents* web_contents = web_contents_getter.Run();
- if (!web_contents)
- return;
-
- WebContentsDelegateQt *contentsDelegate = static_cast<WebContentsDelegateQt*>(web_contents->GetDelegate());
- if (!contentsDelegate)
- return;
-
- WebEngineSettings *settings = contentsDelegate->webEngineSettings();
- if (!settings->testAttribute(WebEngineSettings::PdfViewerEnabled)
- || !settings->testAttribute(WebEngineSettings::PluginsEnabled)) {
- // If the applications has been set up to always download PDF files to open them in an
- // external viewer, trigger the download.
- std::unique_ptr<download::DownloadUrlParameters> params(
- content::DownloadRequestUtils::CreateDownloadForWebContentsMainFrame(
- web_contents, original_url, MISSING_TRAFFIC_ANNOTATION));
- content::BrowserContext::GetDownloadManager(web_contents->GetBrowserContext())
- ->DownloadUrl(std::move(params));
- return;
- }
-
- // The URL passes the original pdf resource url, that will be requested
- // by the pdf viewer extension page.
- content::NavigationController::LoadURLParams params(
- GURL(base::StringPrintf("%s://%s/index.html?%s", extensions::kExtensionScheme,
- extension_id.c_str(),
- original_url.spec().c_str())));
-
- params.frame_tree_node_id = frame_tree_node_id;
- web_contents->GetController().LoadURLWithParams(params);
-}
-
-bool ResourceDispatcherHostDelegateQt::ShouldInterceptResourceAsStream(net::URLRequest *request,
- const std::string &mime_type,
- GURL *origin,
- std::string *payload)
-{
- content::ResourceRequestInfo* info =
- content::ResourceRequestInfo::ForRequest(request);
-
- int render_process_host_id = -1;
- int render_frame_id = -1;
- if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_host_id, &render_frame_id))
- return false;
-
- std::vector<std::string> whitelist = MimeTypesHandler::GetMIMETypeWhitelist();
-
- extensions::ExtensionSystemQt *extensionSystem = ProfileIODataQt::FromResourceContext(info->GetContext())->GetExtensionSystem();
- if (!extensionSystem)
- return false;
-
- const scoped_refptr<const extensions::InfoMap> extension_info_map(extensionSystem->info_map());
-
- for (const std::string &extension_id : whitelist) {
- const extensions::Extension *extension = extension_info_map->extensions().GetByID(extension_id);
- if (!extension)
- continue;
-
- MimeTypesHandler* handler = MimeTypesHandler::GetHandler(extension);
- if (!handler)
- continue;
- if (handler->CanHandleMIMEType(mime_type)) {
- StreamTargetInfo target_info;
- *origin = extensions::Extension::GetBaseURLFromExtensionId(extension_id);
- target_info.extension_id = extension_id;
- target_info.view_id = base::GenerateGUID();
- *payload = target_info.view_id;
- stream_target_info_[request] = target_info;
- return true;
- }
- }
- return false;
-}
-
-// Informs the delegate that a Stream was created. The Stream can be read from
-// the blob URL of the Stream, but can only be read once.
-void ResourceDispatcherHostDelegateQt::OnStreamCreated(net::URLRequest *request,
- std::unique_ptr<content::StreamInfo> stream)
-{
- content::ResourceRequestInfo *info = content::ResourceRequestInfo::ForRequest(request);
- std::map<net::URLRequest *, StreamTargetInfo>::iterator ix = stream_target_info_.find(request);
- CHECK(ix != stream_target_info_.end());
- int render_frame_id = -1;
- int render_process_id = -1;
- if (!content::ResourceRequestInfo::GetRenderFrameForRequest(request, &render_process_id, &render_frame_id)) {
- stream_target_info_.erase(request);
- request->Cancel();
- return;
- }
-
- base::PostTaskWithTraits(
- FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&OnPdfStreamIntercepted,
- request->url(), ix->second.extension_id,
- info->GetFrameTreeNodeId(), info->GetWebContentsGetterForRequest()
- )
- );
- stream_target_info_.erase(request);
-}
-
-} // namespace QtWebEngineCore
diff --git a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h b/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h
deleted file mode 100644
index 3039fd03e..000000000
--- a/src/core/renderer_host/resource_dispatcher_host_delegate_qt.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H
-#define RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H
-
-#include "content/public/browser/resource_dispatcher_host_delegate.h"
-#include "extensions/buildflags/buildflags.h"
-
-#include "web_contents_adapter_client.h"
-
-namespace QtWebEngineCore {
-
-class ResourceDispatcherHostDelegateQt : public content::ResourceDispatcherHostDelegate {
-public:
- // If the stream will be rendered in a BrowserPlugin, |payload| will contain
- // the data that should be given to the old ResourceHandler to forward to the
- // renderer process.
- bool ShouldInterceptResourceAsStream(net::URLRequest *request,
- const std::string &mime_type,
- GURL *origin,
- std::string *payload) override;
-
- // Informs the delegate that a Stream was created. The Stream can be read from
- // the blob URL of the Stream, but can only be read once.
- void OnStreamCreated(net::URLRequest *request,
- std::unique_ptr<content::StreamInfo> stream) override;
-private:
-#if BUILDFLAG(ENABLE_EXTENSIONS)
- struct StreamTargetInfo {
- std::string extension_id;
- std::string view_id;
- };
- std::map<net::URLRequest *, StreamTargetInfo> stream_target_info_;
-#endif
-
-};
-
-} // namespace QtWebEngineCore
-
-#endif // RESOURCE_DISPATCHER_HOST_DELEGATE_QT_H
diff --git a/src/core/renderer_host/user_resource_controller_host.cpp b/src/core/renderer_host/user_resource_controller_host.cpp
index ed4d736f2..96625c13f 100644
--- a/src/core/renderer_host/user_resource_controller_host.cpp
+++ b/src/core/renderer_host/user_resource_controller_host.cpp
@@ -51,39 +51,37 @@
namespace QtWebEngineCore {
-class UserResourceControllerHost::WebContentsObserverHelper : public content::WebContentsObserver {
+class UserResourceControllerHost::WebContentsObserverHelper : public content::WebContentsObserver
+{
public:
WebContentsObserverHelper(UserResourceControllerHost *, content::WebContents *);
// WebContentsObserver overrides:
void RenderFrameCreated(content::RenderFrameHost *renderFrameHost) override;
- void RenderFrameHostChanged(content::RenderFrameHost *oldHost,
- content::RenderFrameHost *newHost) override;
+ void RenderFrameHostChanged(content::RenderFrameHost *oldHost, content::RenderFrameHost *newHost) override;
void WebContentsDestroyed() override;
private:
UserResourceControllerHost *m_controllerHost;
};
-UserResourceControllerHost::WebContentsObserverHelper::WebContentsObserverHelper(UserResourceControllerHost *controller, content::WebContents *contents)
- : content::WebContentsObserver(contents)
- , m_controllerHost(controller)
+UserResourceControllerHost::WebContentsObserverHelper::WebContentsObserverHelper(UserResourceControllerHost *controller,
+ content::WebContents *contents)
+ : content::WebContentsObserver(contents)
+ , m_controllerHost(controller)
{
}
-void UserResourceControllerHost::WebContentsObserverHelper::RenderFrameCreated(
- content::RenderFrameHost *renderFrameHost)
+void UserResourceControllerHost::WebContentsObserverHelper::RenderFrameCreated(content::RenderFrameHost *renderFrameHost)
{
content::WebContents *contents = web_contents();
const QList<UserScript> scripts = m_controllerHost->m_perContentsScripts.value(contents);
for (const UserScript &script : scripts)
- renderFrameHost->Send(new RenderFrameObserverHelper_AddScript(
- renderFrameHost->GetRoutingID(), script.data()));
+ renderFrameHost->Send(new RenderFrameObserverHelper_AddScript(renderFrameHost->GetRoutingID(), script.data()));
}
-void UserResourceControllerHost::WebContentsObserverHelper::RenderFrameHostChanged(
- content::RenderFrameHost *oldHost,
- content::RenderFrameHost *newHost)
+void UserResourceControllerHost::WebContentsObserverHelper::RenderFrameHostChanged(content::RenderFrameHost *oldHost,
+ content::RenderFrameHost *newHost)
{
if (oldHost)
oldHost->Send(new RenderFrameObserverHelper_ClearScripts(oldHost->GetRoutingID()));
@@ -95,10 +93,12 @@ void UserResourceControllerHost::WebContentsObserverHelper::WebContentsDestroyed
delete this;
}
-class UserResourceControllerHost::RenderProcessObserverHelper : public content::RenderProcessHostObserver {
+class UserResourceControllerHost::RenderProcessObserverHelper : public content::RenderProcessHostObserver
+{
public:
RenderProcessObserverHelper(UserResourceControllerHost *);
void RenderProcessHostDestroyed(content::RenderProcessHost *) override;
+
private:
UserResourceControllerHost *m_controllerHost;
};
@@ -142,9 +142,9 @@ void UserResourceControllerHost::addUserScript(const UserScript &script, WebCont
}
}
contents->GetRenderViewHost()->Send(
- new RenderFrameObserverHelper_AddScript(
- contents->GetRenderViewHost()->GetMainFrame()->GetRoutingID(),
- script.data()));
+ new RenderFrameObserverHelper_AddScript(
+ contents->GetRenderViewHost()->GetMainFrame()->GetRoutingID(),
+ script.data()));
}
}
@@ -165,8 +165,7 @@ bool UserResourceControllerHost::removeUserScript(const UserScript &script, WebC
return false;
const bool isProfileWideScript = !adapter;
if (isProfileWideScript) {
- QList<UserScript>::iterator it
- = std::find(m_profileWideScripts.begin(), m_profileWideScripts.end(), script);
+ QList<UserScript>::iterator it = std::find(m_profileWideScripts.begin(), m_profileWideScripts.end(), script);
if (it == m_profileWideScripts.end())
return false;
for (content::RenderProcessHost *renderer : qAsConst(m_observedProcesses))
@@ -181,9 +180,7 @@ bool UserResourceControllerHost::removeUserScript(const UserScript &script, WebC
if (it == list.end())
return false;
contents->GetRenderViewHost()->Send(
- new RenderFrameObserverHelper_RemoveScript(
- contents->GetMainFrame()->GetRoutingID(),
- (*it).data()));
+ new RenderFrameObserverHelper_RemoveScript(contents->GetMainFrame()->GetRoutingID(), (*it).data()));
list.erase(it);
}
return true;
@@ -200,7 +197,7 @@ void UserResourceControllerHost::clearAllScripts(WebContentsAdapter *adapter)
content::WebContents *contents = adapter->webContents();
m_perContentsScripts.remove(contents);
contents->GetRenderViewHost()->Send(
- new RenderFrameObserverHelper_ClearScripts(contents->GetMainFrame()->GetRoutingID()));
+ new RenderFrameObserverHelper_ClearScripts(contents->GetMainFrame()->GetRoutingID()));
}
}
diff --git a/src/core/renderer_host/user_resource_controller_host.h b/src/core/renderer_host/user_resource_controller_host.h
index 16a73f5fb..9d828feb6 100644
--- a/src/core/renderer_host/user_resource_controller_host.h
+++ b/src/core/renderer_host/user_resource_controller_host.h
@@ -66,7 +66,8 @@ namespace QtWebEngineCore {
class WebContentsAdapter;
-class Q_WEBENGINECORE_PRIVATE_EXPORT UserResourceControllerHost {
+class Q_WEBENGINECORE_PRIVATE_EXPORT UserResourceControllerHost
+{
public:
UserResourceControllerHost();
diff --git a/src/core/renderer_host/web_channel_ipc_transport_host.cpp b/src/core/renderer_host/web_channel_ipc_transport_host.cpp
index 9758f73bf..c071a566a 100644
--- a/src/core/renderer_host/web_channel_ipc_transport_host.cpp
+++ b/src/core/renderer_host/web_channel_ipc_transport_host.cpp
@@ -54,11 +54,6 @@
namespace QtWebEngineCore {
-enum {
- // sizeof(QJsonPrivate::Header) + sizeof(QJsonPrivate::Base)
- MinimumBinaryJsonSize = 8 + 12
-};
-
Q_LOGGING_CATEGORY(log, "qt.webengine.webchanneltransport")
inline QDebug operator<<(QDebug stream, content::RenderFrameHost *frame)
@@ -66,7 +61,7 @@ inline QDebug operator<<(QDebug stream, content::RenderFrameHost *frame)
return stream << "frame " << frame->GetRoutingID() << " in process " << frame->GetProcess()->GetID();
}
-template <class T>
+template<class T>
inline QDebug operator<<(QDebug stream, const base::Optional<T> &opt)
{
if (opt)
@@ -101,7 +96,7 @@ void WebChannelIPCTransportHost::sendMessage(const QJsonObject &message)
int size = 0;
const char *rawData = doc.rawData(&size);
content::RenderFrameHost *frame = web_contents()->GetMainFrame();
- qtwebchannel::mojom::WebChannelTransportRenderAssociatedPtr webChannelTransport;
+ mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportRender> webChannelTransport;
frame->GetRemoteAssociatedInterfaces()->GetInterface(&webChannelTransport);
qCDebug(log).nospace() << "sending webchannel message to " << frame << ": " << doc;
webChannelTransport->DispatchWebChannelMessage(std::vector<uint8_t>(rawData, rawData + size), m_worldId);
@@ -121,7 +116,7 @@ void WebChannelIPCTransportHost::setWorldId(content::RenderFrameHost *frame, uin
if (!frame->IsRenderFrameLive())
return;
qCDebug(log).nospace() << "sending setWorldId(" << worldId << ") message to " << frame;
- qtwebchannel::mojom::WebChannelTransportRenderAssociatedPtr webChannelTransport;
+ mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportRender> webChannelTransport;
frame->GetRemoteAssociatedInterfaces()->GetInterface(&webChannelTransport);
webChannelTransport->SetWorldId(worldId);
}
@@ -131,7 +126,7 @@ void WebChannelIPCTransportHost::resetWorldId()
for (content::RenderFrameHost *frame : web_contents()->GetAllFrames()) {
if (!frame->IsRenderFrameLive())
return;
- qtwebchannel::mojom::WebChannelTransportRenderAssociatedPtr webChannelTransport;
+ mojo::AssociatedRemote<qtwebchannel::mojom::WebChannelTransportRender> webChannelTransport;
frame->GetRemoteAssociatedInterfaces()->GetInterface(&webChannelTransport);
webChannelTransport->ResetWorldId();
}
@@ -145,12 +140,7 @@ void WebChannelIPCTransportHost::DispatchWebChannelMessage(const std::vector<uin
return;
}
- QJsonDocument doc;
- // QJsonDocument::fromRawData does not check the length before it starts
- // parsing the QJsonPrivate::Header and QJsonPrivate::Base structures.
- if (binaryJson.size() >= MinimumBinaryJsonSize)
- doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()),
- binaryJson.size());
+ QJsonDocument doc = QJsonDocument::fromRawData(reinterpret_cast<const char *>(binaryJson.data()), binaryJson.size());
if (!doc.isObject()) {
qCCritical(log).nospace() << "received invalid webchannel message from " << frame;
diff --git a/src/core/renderer_host/web_channel_ipc_transport_host.h b/src/core/renderer_host/web_channel_ipc_transport_host.h
index 94891f25f..d53b24b6b 100644
--- a/src/core/renderer_host/web_channel_ipc_transport_host.h
+++ b/src/core/renderer_host/web_channel_ipc_transport_host.h
@@ -53,9 +53,11 @@ QT_FORWARD_DECLARE_CLASS(QString)
namespace QtWebEngineCore {
-class WebChannelIPCTransportHost : public QWebChannelAbstractTransport
+class WebChannelIPCTransportHost
+ : public QWebChannelAbstractTransport
, private content::WebContentsObserver
- , qtwebchannel::mojom::WebChannelTransportHost {
+ , qtwebchannel::mojom::WebChannelTransportHost
+{
public:
WebChannelIPCTransportHost(content::WebContents *webContents, uint32_t worldId = 0, QObject *parent = nullptr);
~WebChannelIPCTransportHost() override;
diff --git a/src/core/service/service_qt.cpp b/src/core/service/service_qt.cpp
deleted file mode 100644
index 83948e396..000000000
--- a/src/core/service/service_qt.cpp
+++ /dev/null
@@ -1,169 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-// based on chrome/browser/chrome_service.cc:
-// Copyright 2017 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 file.
-
-#include "service_qt.h"
-
-#include "base/no_destructor.h"
-#include "base/task/post_task.h"
-#include "components/spellcheck/spellcheck_buildflags.h"
-#include "content/public/browser/browser_task_traits.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/content_browser_client.h"
-#include "services/service_manager/public/cpp/binder_registry.h"
-#include "services/service_manager/public/cpp/connector.h"
-#include "services/service_manager/public/cpp/service.h"
-#include "services/service_manager/public/cpp/service_binding.h"
-
-#if BUILDFLAG(ENABLE_SPELLCHECK)
-#include "chrome/browser/spellchecker/spell_check_host_chrome_impl.h"
-#endif
-
-class ServiceQt::IOThreadContext : public service_manager::Service {
-public:
- IOThreadContext();
- ~IOThreadContext() override = default;
-
- void BindServiceRequest(service_manager::mojom::ServiceRequest request);
- void BindConnector(service_manager::mojom::ConnectorRequest connector_request);
-
-private:
- void BindConnectorOnIOThread(service_manager::mojom::ConnectorRequest connector_request);
-
- // service_manager::Service:
- void OnStart() override;
- void OnBindInterface(const service_manager::BindSourceInfo &remote_info,
- const std::string &name,
- mojo::ScopedMessagePipeHandle handle) override;
-
- service_manager::mojom::ConnectorRequest m_connectorRequest;
- service_manager::ServiceBinding m_serviceBinding{this};
- service_manager::BinderRegistry m_registry;
- service_manager::BinderRegistryWithArgs<const service_manager::BindSourceInfo&> m_registry_with_source_info;
-
- DISALLOW_COPY_AND_ASSIGN(IOThreadContext);
-};
-
-ServiceQt::IOThreadContext::IOThreadContext()
-{
-#if BUILDFLAG(ENABLE_SPELLCHECK)
- scoped_refptr<base::SingleThreadTaskRunner> ui_task_runner =
- base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::UI});
- m_registry_with_source_info.AddInterface(base::BindRepeating(&SpellCheckHostChromeImpl::Create), ui_task_runner);
-#endif
-}
-
-void ServiceQt::IOThreadContext::BindServiceRequest(service_manager::mojom::ServiceRequest request)
-{
- m_serviceBinding.Bind(std::move(request));
-}
-
-void ServiceQt::IOThreadContext::BindConnector(service_manager::mojom::ConnectorRequest connector_request)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-
- // NOTE: It's not safe to modify |connector_request_| here since it's read
- // on the IO thread. Post a task instead. As long as this task is posted
- // before any code attempts to connect to the chrome service, there's no
- // race.
- base::CreateSingleThreadTaskRunnerWithTraits({content::BrowserThread::IO})->PostTask(
- FROM_HERE,
- base::BindOnce(&IOThreadContext::BindConnectorOnIOThread,
- base::Unretained(this),
- std::move(connector_request)));
-}
-
-void ServiceQt::IOThreadContext::BindConnectorOnIOThread(service_manager::mojom::ConnectorRequest connector_request)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- m_connectorRequest = std::move(connector_request);
-}
-
-void ServiceQt::IOThreadContext::OnStart()
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- DCHECK(m_connectorRequest.is_pending());
- m_serviceBinding.GetConnector()->BindConnectorRequest(std::move(m_connectorRequest));
-}
-
-void ServiceQt::IOThreadContext::OnBindInterface(const service_manager::BindSourceInfo &remote_info,
- const std::string &name,
- mojo::ScopedMessagePipeHandle handle)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- content::OverrideOnBindInterface(remote_info, name, &handle);
- if (!handle.is_valid())
- return;
-
- if (!m_registry.TryBindInterface(name, &handle))
- m_registry_with_source_info.TryBindInterface(name, &handle, remote_info);
-}
-
-ServiceQt *ServiceQt::GetInstance()
-{
- static base::NoDestructor<ServiceQt> service;
- return service.get();
-}
-
-content::ServiceManagerConnection::ServiceRequestHandler ServiceQt::CreateServiceQtRequestHandler()
-{
- return base::BindRepeating(&ServiceQt::BindServiceQtRequest, base::Unretained(this));
-}
-
-ServiceQt::ServiceQt() : m_ioThreadContext(std::make_unique<IOThreadContext>())
-{}
-
-ServiceQt::~ServiceQt() = default;
-
-void ServiceQt::InitConnector()
-{
- service_manager::mojom::ConnectorRequest request;
- m_connector = service_manager::Connector::Create(&request);
- m_ioThreadContext->BindConnector(std::move(request));
-}
-
-void ServiceQt::BindServiceQtRequest(service_manager::mojom::ServiceRequest request)
-{
- DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
- m_ioThreadContext->BindServiceRequest(std::move(request));
-}
diff --git a/src/core/service/service_qt.h b/src/core/service/service_qt.h
deleted file mode 100644
index d4c89065c..000000000
--- a/src/core/service/service_qt.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtWebEngine module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef SERVICE_QT_H
-#define SERVICE_QT_H
-
-#include "base/no_destructor.h"
-#include "content/public/common/service_manager_connection.h"
-
-namespace service_manager {
-class Connector;
-class Service;
-} // namespace service_manager
-
-class ServiceQt {
-public:
- static ServiceQt *GetInstance();
-
- void InitConnector();
- content::ServiceManagerConnection::ServiceRequestHandler CreateServiceQtRequestHandler();
- service_manager::Connector *connector() { return m_connector.get(); }
-
-private:
- friend class base::NoDestructor<ServiceQt>;
- class IOThreadContext;
-
- ServiceQt();
- ~ServiceQt();
-
- void BindServiceQtRequest(service_manager::mojom::ServiceRequest request);
-
- const std::unique_ptr<IOThreadContext> m_ioThreadContext;
-
- std::unique_ptr<service_manager::Connector> m_connector;
-
- DISALLOW_COPY_AND_ASSIGN(ServiceQt);
-};
-
-#endif // SERVICE_QT_H
diff --git a/src/core/type_conversion.cpp b/src/core/type_conversion.cpp
index aea924dbd..403125784 100644
--- a/src/core/type_conversion.cpp
+++ b/src/core/type_conversion.cpp
@@ -59,6 +59,11 @@ QImage toQImage(const SkBitmap &bitmap)
case kRGBA_F16_SkColorType:
case kRGBA_F32_SkColorType:
case kRGBA_F16Norm_SkColorType:
+ case kR8G8_unorm_SkColorType:
+ case kA16_float_SkColorType:
+ case kA16_unorm_SkColorType:
+ case kR16G16_float_SkColorType:
+ case kR16G16_unorm_SkColorType:
qWarning("Unknown or unsupported skia image format");
break;
case kAlpha_8_SkColorType:
@@ -131,6 +136,21 @@ QImage toQImage(const SkBitmap &bitmap)
case kGray_8_SkColorType:
image = toQImage(bitmap, QImage::Format_Grayscale8);
break;
+ case kR16G16B16A16_unorm_SkColorType:
+ switch (bitmap.alphaType()) {
+ case kUnknown_SkAlphaType:
+ break;
+ case kUnpremul_SkAlphaType:
+ image = toQImage(bitmap, QImage::Format_RGBA64);
+ break;
+ case kOpaque_SkAlphaType:
+ image = toQImage(bitmap, QImage::Format_RGBX64);
+ break;
+ case kPremul_SkAlphaType:
+ image = toQImage(bitmap, QImage::Format_RGBA64_Premultiplied);
+ break;
+ }
+ break;
}
return image;
}
diff --git a/src/core/user_notification_controller.cpp b/src/core/user_notification_controller.cpp
index 50d12e8fd..f94605a55 100644
--- a/src/core/user_notification_controller.cpp
+++ b/src/core/user_notification_controller.cpp
@@ -43,6 +43,7 @@
#include "base/callback.h"
#include "content/public/browser/notification_event_dispatcher.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom-shared.h"
#include "third_party/blink/public/common/notifications/notification_resources.h"
#include "third_party/blink/public/common/notifications/platform_notification_data.h"
#include "ui/message_center/public/cpp/notification_delegate.h"
diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp
index 31731fe99..138ea7039 100644
--- a/src/core/web_contents_adapter.cpp
+++ b/src/core/web_contents_adapter.cpp
@@ -85,8 +85,9 @@
#include "content/public/common/page_zoom.h"
#include "content/public/common/url_constants.h"
#include "content/public/common/web_preferences.h"
-#include "content/public/common/webrtc_ip_handling_policy.h"
#include "extensions/buildflags/buildflags.h"
+#include "third_party/blink/public/common/page/page_zoom.h"
+#include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h"
#include "third_party/blink/public/web/web_media_player_action.h"
#include "printing/buildflags/buildflags.h"
#include "ui/base/clipboard/clipboard.h"
@@ -240,7 +241,6 @@ static std::unique_ptr<content::WebContents> createBlankWebContents(WebContentsA
{
content::WebContents::CreateParams create_params(browserContext, NULL);
create_params.routing_id = MSG_ROUTING_NONE;
- create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight);
create_params.initially_hidden = true;
std::unique_ptr<content::WebContents> webContents = content::WebContents::Create(create_params);
@@ -502,7 +502,6 @@ void WebContentsAdapter::initialize(content::SiteInstance *site)
// Create our own if a WebContents wasn't provided at construction.
if (!m_webContents) {
content::WebContents::CreateParams create_params(m_profileAdapter->profile(), site);
- create_params.initial_size = gfx::Size(kTestWindowWidth, kTestWindowHeight);
create_params.initially_hidden = true;
m_webContents = content::WebContents::Create(create_params);
}
@@ -563,8 +562,8 @@ void WebContentsAdapter::initializeRenderPrefs()
else
rendererPrefs->webrtc_ip_handling_policy =
m_adapterClient->webEngineSettings()->testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly)
- ? content::kWebRTCIPHandlingDefaultPublicInterfaceOnly
- : content::kWebRTCIPHandlingDefault;
+ ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly
+ : blink::kWebRTCIPHandlingDefault;
#endif
// 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.
@@ -575,7 +574,7 @@ void WebContentsAdapter::initializeRenderPrefs()
rendererPrefs->use_autohinter = params.autohinter;
rendererPrefs->use_bitmaps = params.use_bitmaps;
rendererPrefs->subpixel_rendering = params.subpixel_rendering;
- m_webContents->GetRenderViewHost()->SyncRendererPrefs();
+ m_webContents->SyncRendererPrefs();
}
bool WebContentsAdapter::canGoBack() const
@@ -725,8 +724,8 @@ void WebContentsAdapter::load(const QWebEngineHttpRequest &request)
if (resizeNeeded) {
// Schedule navigation on the event loop.
- base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
- base::BindOnce(&NavigateTask, sharedFromThis().toWeakRef(), std::move(params)));
+ base::PostTask(FROM_HERE, {content::BrowserThread::UI},
+ base::BindOnce(&NavigateTask, sharedFromThis().toWeakRef(), std::move(params)));
} else {
Navigate(this, params);
}
@@ -974,10 +973,10 @@ void WebContentsAdapter::serializeNavigationHistory(QDataStream &output)
void WebContentsAdapter::setZoomFactor(qreal factor)
{
CHECK_INITIALIZED();
- if (factor < content::kMinimumZoomFactor || factor > content::kMaximumZoomFactor)
+ if (factor < blink::kMinimumPageZoomFactor || factor > blink::kMaximumPageZoomFactor)
return;
- double zoomLevel = content::ZoomFactorToZoomLevel(static_cast<double>(factor));
+ double zoomLevel = blink::PageZoomFactorToZoomLevel(static_cast<double>(factor));
content::HostZoomMap *zoomMap = content::HostZoomMap::GetForWebContents(m_webContents.get());
if (zoomMap) {
@@ -990,7 +989,7 @@ void WebContentsAdapter::setZoomFactor(qreal factor)
qreal WebContentsAdapter::currentZoomFactor() const
{
CHECK_INITIALIZED(1);
- return content::ZoomLevelToZoomFactor(content::HostZoomMap::GetZoomLevel(m_webContents.get()));
+ return blink::PageZoomLevelToZoomFactor(content::HostZoomMap::GetZoomLevel(m_webContents.get()));
}
ProfileQt* WebContentsAdapter::profile()
@@ -1149,6 +1148,17 @@ bool WebContentsAdapter::recentlyAudible() const
return m_webContents->IsCurrentlyAudible();
}
+qint64 WebContentsAdapter::renderProcessPid() const
+{
+ CHECK_INITIALIZED(0);
+
+ content::RenderProcessHost *renderProcessHost = m_webContents->GetMainFrame()->GetProcess();
+ const base::Process &process = renderProcessHost->GetProcess();
+ if (!process.IsValid())
+ return 0;
+ return process.Pid();
+}
+
void WebContentsAdapter::copyImageAt(const QPoint &location)
{
CHECK_INITIALIZED();
diff --git a/src/core/web_contents_adapter.h b/src/core/web_contents_adapter.h
index f8f147f9a..ef9d21b8f 100644
--- a/src/core/web_contents_adapter.h
+++ b/src/core/web_contents_adapter.h
@@ -166,6 +166,7 @@ public:
bool isAudioMuted() const;
void setAudioMuted(bool mute);
bool recentlyAudible() const;
+ qint64 renderProcessPid() const;
// Must match blink::WebMediaPlayerAction::Type.
enum MediaPlayerAction {
diff --git a/src/core/web_contents_adapter_client.h b/src/core/web_contents_adapter_client.h
index e2f667358..3a75185f8 100644
--- a/src/core/web_contents_adapter_client.h
+++ b/src/core/web_contents_adapter_client.h
@@ -458,6 +458,7 @@ public:
virtual void didUpdateTargetURL(const QUrl&) = 0;
virtual void selectionChanged() = 0;
virtual void recentlyAudibleChanged(bool recentlyAudible) = 0;
+ virtual void renderProcessPidChanged(qint64 pid) = 0;
virtual QRectF viewportRect() const = 0;
virtual QColor backgroundColor() const = 0;
virtual void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) = 0;
diff --git a/src/core/web_contents_delegate_qt.cpp b/src/core/web_contents_delegate_qt.cpp
index 7b339776b..e97536593 100644
--- a/src/core/web_contents_delegate_qt.cpp
+++ b/src/core/web_contents_delegate_qt.cpp
@@ -49,7 +49,6 @@
#include "favicon_manager.h"
#include "file_picker_controller.h"
#include "media_capture_devices_dispatcher.h"
-#include "net/network_delegate_qt.h"
#include "profile_qt.h"
#include "qwebengineregisterprotocolhandlerrequest.h"
#include "register_protocol_handler_request_controller_impl.h"
@@ -316,6 +315,14 @@ void WebContentsDelegateQt::RenderFrameHostChanged(content::RenderFrameHost *old
if (new_host) {
content::FrameTreeNode *new_node = static_cast<content::RenderFrameHostImpl *>(new_host)->frame_tree_node();
m_frameFocusedObserver.addNode(new_node);
+
+ // Is this a main frame?
+ if (new_host->GetFrameOwnerElementType() == blink::FrameOwnerElementType::kNone) {
+ content::RenderProcessHost *renderProcessHost = new_host->GetProcess();
+ const base::Process &process = renderProcessHost->GetProcess();
+ if (process.IsValid())
+ m_viewClient->renderProcessPidChanged(process.Pid());
+ }
}
}
@@ -476,11 +483,12 @@ void WebContentsDelegateQt::DidFinishLoad(content::RenderFrameHost* render_frame
Q_ASSERT(validated_url.is_valid());
if (validated_url.spec() == content::kUnreachableWebDataURL) {
m_loadingErrorFrameList.removeOne(render_frame_host->GetRoutingID());
- m_viewClient->iconChanged(QUrl());
// Trigger LoadFinished signal for main frame's error page only.
- if (!render_frame_host->GetParent())
+ if (!render_frame_host->GetParent()) {
+ m_viewClient->iconChanged(QUrl());
EmitLoadFinished(true /* success */, toQt(validated_url), true /* isErrorPage */);
+ }
return;
}
@@ -538,7 +546,7 @@ content::JavaScriptDialogManager *WebContentsDelegateQt::GetJavaScriptDialogMana
return JavaScriptDialogManagerQt::GetInstance();
}
-void WebContentsDelegateQt::EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL& origin, const blink::WebFullscreenOptions &)
+void WebContentsDelegateQt::EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL& origin, const blink::mojom::FullscreenOptions &)
{
Q_UNUSED(web_contents);
if (!m_viewClient->isFullScreenMode())
diff --git a/src/core/web_contents_delegate_qt.h b/src/core/web_contents_delegate_qt.h
index 33fd49b3d..6818fa551 100644
--- a/src/core/web_contents_delegate_qt.h
+++ b/src/core/web_contents_delegate_qt.h
@@ -128,7 +128,7 @@ public:
void WebContentsCreated(content::WebContents *source_contents, int opener_render_process_id, int opener_render_frame_id,
const std::string &frame_name, const GURL &target_url, content::WebContents *new_contents) override;
content::JavaScriptDialogManager *GetJavaScriptDialogManager(content::WebContents *source) override;
- void EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL &origin, const blink::WebFullscreenOptions &) override;
+ void EnterFullscreenModeForTab(content::WebContents *web_contents, const GURL &origin, const blink::mojom::FullscreenOptions &options) override;
void ExitFullscreenModeForTab(content::WebContents*) override;
bool IsFullscreenForTabOrPending(const content::WebContents* web_contents) override;
void RunFileChooser(content::RenderFrameHost* render_frame_host,
diff --git a/src/core/web_contents_view_qt.cpp b/src/core/web_contents_view_qt.cpp
index e50835f74..139450cd8 100644
--- a/src/core/web_contents_view_qt.cpp
+++ b/src/core/web_contents_view_qt.cpp
@@ -111,7 +111,7 @@ content::RenderWidgetHostViewBase* WebContentsViewQt::CreateViewForChildWidget(c
return view;
}
-void WebContentsViewQt::CreateView(const gfx::Size& initial_size, gfx::NativeView context)
+void WebContentsViewQt::CreateView(gfx::NativeView context)
{
}
diff --git a/src/core/web_contents_view_qt.h b/src/core/web_contents_view_qt.h
index 978a2ce2e..6f5ffdb86 100644
--- a/src/core/web_contents_view_qt.h
+++ b/src/core/web_contents_view_qt.h
@@ -72,7 +72,7 @@ public:
// content::WebContentsView overrides:
content::RenderWidgetHostViewBase *CreateViewForWidget(content::RenderWidgetHost* render_widget_host, bool is_guest_view_hack) override;
- void CreateView(const gfx::Size& initial_size, gfx::NativeView context) override;
+ void CreateView(gfx::NativeView context) override;
content::RenderWidgetHostViewBase *CreateViewForChildWidget(content::RenderWidgetHost* render_widget_host) override;
diff --git a/src/core/web_engine_context.cpp b/src/core/web_engine_context.cpp
index 286842a20..5937d3b21 100644
--- a/src/core/web_engine_context.cpp
+++ b/src/core/web_engine_context.cpp
@@ -47,8 +47,10 @@
#include "base/run_loop.h"
#include "base/task/post_task.h"
#include "base/task/sequence_manager/thread_controller_with_message_pump_impl.h"
+#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/threading/thread_restrictions.h"
#include "cc/base/switches.h"
+#include "chrome/common/chrome_switches.h"
#include "content/gpu/gpu_child_thread.h"
#include "content/browser/compositor/surface_utils.h"
#include "components/viz/host/host_frame_sink_manager.h"
@@ -76,6 +78,7 @@
#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 "gpu/command_buffer/service/gpu_switches.h"
#include "gpu/command_buffer/service/sync_point_manager.h"
#include "media/audio/audio_manager.h"
@@ -85,8 +88,9 @@
#include "ppapi/buildflags/buildflags.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/network_switches.h"
-#include "services/resource_coordinator/public/cpp/resource_coordinator_features.h"
+#include "services/network/public/mojom/network_context.mojom.h"
#include "services/service_manager/sandbox/switches.h"
+#include "services/tracing/public/cpp/trace_startup.h"
#include "services/tracing/public/cpp/tracing_features.h"
#include "third_party/blink/public/common/features.h"
#include "ui/events/event_switches.h"
@@ -214,6 +218,26 @@ bool usingSoftwareDynamicGL()
#endif
}
+void setupProxyPac(base::CommandLine *commandLine){
+ if (commandLine->HasSwitch(switches::kProxyPacUrl)) {
+ QUrl pac_url(toQt(commandLine->GetSwitchValueASCII(switches::kProxyPacUrl)));
+ if (pac_url.isValid() && (pac_url.isLocalFile() ||
+ !pac_url.scheme().compare(QLatin1String("qrc"), Qt::CaseInsensitive))) {
+ QFile file;
+ if (pac_url.isLocalFile())
+ file.setFileName(pac_url.toLocalFile());
+ else
+ file.setFileName(pac_url.path().prepend(QChar(':')));
+ if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QByteArray ba = file.readAll();
+ commandLine->RemoveSwitch(switches::kProxyPacUrl);
+ commandLine->AppendSwitchASCII(switches::kProxyPacUrl,
+ ba.toBase64().prepend("data:application/x-javascript-config;base64,").toStdString());
+ }
+ }
+ }
+}
+
static bool waitForViz = false;
static void completeVizCleanup()
{
@@ -491,7 +515,7 @@ WebEngineContext::WebEngineContext()
#endif
base::CommandLine* parsedCommandLine = commandLine();
-
+ setupProxyPac(parsedCommandLine);
parsedCommandLine->AppendSwitchPath(switches::kBrowserSubprocessPath, WebEngineLibraryInfo::getPath(content::CHILD_PROCESS_EXE));
// Enable sandboxing on OS X and Linux (Desktop / Embedded) by default.
@@ -506,20 +530,6 @@ WebEngineContext::WebEngineContext()
}
parsedCommandLine->AppendSwitch(switches::kEnableThreadedCompositing);
- // These are currently only default on OS X, and we don't support them:
- parsedCommandLine->AppendSwitch(switches::kDisableZeroCopy);
- parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferCompositorResources);
-
- // Enabled on OS X and Linux but currently not working. It worked in 5.7 on OS X.
- parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferVideoFrames);
-
-#if defined(Q_OS_MACOS)
- // Accelerated decoding currently does not work on macOS due to issues with OpenGL Rectangle
- // texture support. See QTBUG-60002.
- parsedCommandLine->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
- // Same problem with Pepper using OpenGL images.
- parsedCommandLine->AppendSwitch(switches::kDisablePepper3DImageChromium);
-#endif
#if defined(Q_OS_WIN)
// This switch is used in Chromium's gl_context_wgl.cc file to determine whether to create
@@ -547,6 +557,11 @@ WebEngineContext::WebEngineContext()
bool threadedGpu = false;
#ifndef QT_NO_OPENGL
threadedGpu = QOpenGLContext::supportsThreadedOpenGL();
+#if defined(Q_OS_MACOS)
+ // QtBase disabled it when building on 10.14+, unfortunately we still need it
+ // until we have fixed single-threaded viz-display-compositor.
+ threadedGpu = true;
+#endif
#endif
threadedGpu = threadedGpu && !qEnvironmentVariableIsSet(kDisableInProcGpuThread);
@@ -568,10 +583,10 @@ WebEngineContext::WebEngineContext()
// The video-capture service is not functioning at this moment (since 69)
appendToFeatureList(disableFeatures, features::kMojoVideoCapture.name);
- // We do not yet support the network-service, but it is enabled by default since 75.
- appendToFeatureList(disableFeatures, network::features::kNetworkService.name);
- // BlinkGenPropertyTrees is enabled by default in 75, but causes regressions.
- appendToFeatureList(disableFeatures, blink::features::kBlinkGenPropertyTrees.name);
+#if defined(Q_OS_LINUX)
+ // broken and crashy (even upstream):
+ appendToFeatureList(disableFeatures, features::kFontSrcLocalMatching.name);
+#endif
#if QT_CONFIG(webengine_printing_and_pdf)
appendToFeatureList(disableFeatures, printing::features::kUsePdfCompositorServiceForPrint.name);
@@ -579,12 +594,12 @@ WebEngineContext::WebEngineContext()
// Explicitly tell Chromium about default-on features we do not support
appendToFeatureList(disableFeatures, features::kBackgroundFetch.name);
- appendToFeatureList(disableFeatures, features::kOriginTrials.name);
appendToFeatureList(disableFeatures, features::kSmsReceiver.name);
appendToFeatureList(disableFeatures, features::kWebAuth.name);
appendToFeatureList(disableFeatures, features::kWebAuthCable.name);
appendToFeatureList(disableFeatures, features::kWebPayments.name);
appendToFeatureList(disableFeatures, features::kWebUsb.name);
+ appendToFeatureList(disableFeatures, media::kPictureInPicture.name);
if (useEmbeddedSwitches) {
// embedded switches are based on the switches for Android, see content/browser/android/content_startup_flags.cc
@@ -595,6 +610,21 @@ WebEngineContext::WebEngineContext()
}
if (!enableViz) {
+ // These are currently only default on OS X, and we don't support them:
+ parsedCommandLine->AppendSwitch(switches::kDisableZeroCopy);
+ parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferCompositorResources);
+
+ // Enabled on OS X and Linux but currently not working. It worked in 5.7 on OS X.
+ parsedCommandLine->AppendSwitch(switches::kDisableGpuMemoryBufferVideoFrames);
+
+#if defined(Q_OS_MACOS)
+ // Accelerated decoding currently does not work on macOS due to issues with OpenGL Rectangle
+ // texture support. See QTBUG-60002.
+ parsedCommandLine->AppendSwitch(switches::kDisableAcceleratedVideoDecode);
+ // Same problem with Pepper using OpenGL images.
+ parsedCommandLine->AppendSwitch(switches::kDisablePepper3DImageChromium);
+#endif
+
// Viz Display Compositor is enabled by default since 73. Doesn't work for us (also implies SurfaceSynchronization)
appendToFeatureList(disableFeatures, features::kVizDisplayCompositor.name);
// VideoSurfaceLayer is enabled by default since 75. We don't support it.
@@ -715,6 +745,7 @@ WebEngineContext::WebEngineContext()
m_mainDelegate->PostEarlyInitialization(false);
content::StartBrowserThreadPool();
content::BrowserTaskExecutor::PostFeatureListSetup();
+ tracing::InitTracingPostThreadPoolStartAndFeatureList();
m_discardableSharedMemoryManager = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>();
m_serviceManagerEnvironment = std::make_unique<content::ServiceManagerEnvironment>(content::BrowserTaskExecutor::CreateIOThread());
m_startupData = m_serviceManagerEnvironment->CreateBrowserStartupData();
diff --git a/src/core/web_engine_context_threads.cpp b/src/core/web_engine_context_threads.cpp
index c7440dd3f..ba3e18499 100644
--- a/src/core/web_engine_context_threads.cpp
+++ b/src/core/web_engine_context_threads.cpp
@@ -65,13 +65,13 @@ struct GpuThreadControllerQt : content::GpuThreadController
{
GpuThreadControllerQt(const content::InProcessChildThreadParams &params, const gpu::GpuPreferences &gpuPreferences)
{
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, { content::BrowserThread::UI },
base::BindOnce(&GpuThreadControllerQt::createGpuProcess, params, gpuPreferences));
}
~GpuThreadControllerQt() override
{
- base::PostTaskWithTraits(
+ base::PostTask(
FROM_HERE, { content::BrowserThread::UI },
base::BindOnce(&GpuThreadControllerQt::destroyGpuProcess));
}
diff --git a/src/core/web_engine_settings.cpp b/src/core/web_engine_settings.cpp
index 49006ec20..eb6db9793 100644
--- a/src/core/web_engine_settings.cpp
+++ b/src/core/web_engine_settings.cpp
@@ -50,8 +50,8 @@
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/web_preferences.h"
-#include "content/public/common/webrtc_ip_handling_policy.h"
#include "media/base/media_switches.h"
+#include "third_party/blink/public/common/peerconnection/webrtc_ip_handling_policy.h"
#include "third_party/blink/public/mojom/renderer_preferences.mojom.h"
#include "ui/base/ui_base_switches.h"
#include "ui/events/event_switches.h"
@@ -128,9 +128,8 @@ void WebEngineSettings::overrideWebPreferences(content::WebContents *webContents
webPreferences.reset(new content::WebPreferences(*prefs));
if (webContents
- && webContents->GetRenderViewHost()
&& applySettingsToRendererPreferences(webContents->GetMutableRendererPrefs())) {
- webContents->GetRenderViewHost()->SyncRendererPrefs();
+ webContents->SyncRendererPrefs();
}
}
@@ -248,7 +247,7 @@ void WebEngineSettings::initDefaults()
s_defaultAttributes.insert(LinksIncludedInFocusChain, true);
s_defaultAttributes.insert(LocalStorageEnabled, true);
s_defaultAttributes.insert(LocalContentCanAccessRemoteUrls, false);
- s_defaultAttributes.insert(XSSAuditingEnabled, true);
+ s_defaultAttributes.insert(XSSAuditingEnabled, false);
s_defaultAttributes.insert(SpatialNavigationEnabled, false);
s_defaultAttributes.insert(LocalContentCanAccessFileUrls, true);
s_defaultAttributes.insert(HyperlinkAuditingEnabled, false);
@@ -340,7 +339,7 @@ void WebEngineSettings::doApply()
m_adapter->updateWebPreferences(*webPreferences.data());
if (applySettingsToRendererPreferences(m_adapter->webContents()->GetMutableRendererPrefs()))
- m_adapter->webContents()->GetRenderViewHost()->SyncRendererPrefs();
+ m_adapter->webContents()->SyncRendererPrefs();
}
void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *prefs)
@@ -366,7 +365,6 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p
prefs->local_storage_enabled = testAttribute(LocalStorageEnabled);
prefs->databases_enabled = testAttribute(LocalStorageEnabled);
prefs->allow_universal_access_from_file_urls = testAttribute(LocalContentCanAccessRemoteUrls);
- prefs->xss_auditor_enabled = testAttribute(XSSAuditingEnabled);
prefs->spatial_navigation_enabled = testAttribute(SpatialNavigationEnabled);
prefs->allow_file_access_from_file_urls = testAttribute(LocalContentCanAccessFileUrls);
prefs->hyperlink_auditing_enabled = testAttribute(HyperlinkAuditingEnabled);
@@ -405,12 +403,6 @@ void WebEngineSettings::applySettingsToWebPreferences(content::WebPreferences *p
// Set the theme colors. Based on chrome_content_browser_client.cc:
const ui::NativeTheme *webTheme = ui::NativeTheme::GetInstanceForWeb();
if (webTheme) {
-#if !defined(OS_MACOSX)
- // Mac has a concept of high contrast that does not relate to forced colors.
- prefs->forced_colors = webTheme->UsesHighContrastColors()
- ? blink::ForcedColors::kActive
- : blink::ForcedColors::kNone;
-#endif // !defined(OS_MACOSX)
switch (webTheme->GetPreferredColorScheme()) {
case ui::NativeTheme::PreferredColorScheme::kDark:
prefs->preferred_color_scheme = blink::PreferredColorScheme::kDark;
@@ -453,8 +445,8 @@ bool WebEngineSettings::applySettingsToRendererPreferences(blink::mojom::Rendere
#if QT_CONFIG(webengine_webrtc)
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) {
std::string webrtc_ip_handling_policy = testAttribute(WebEngineSettings::WebRTCPublicInterfacesOnly)
- ? content::kWebRTCIPHandlingDefaultPublicInterfaceOnly
- : content::kWebRTCIPHandlingDefault;
+ ? blink::kWebRTCIPHandlingDefaultPublicInterfaceOnly
+ : blink::kWebRTCIPHandlingDefault;
if (prefs->webrtc_ip_handling_policy != webrtc_ip_handling_policy) {
prefs->webrtc_ip_handling_policy = webrtc_ip_handling_policy;
changed = true;
diff --git a/src/core/web_event_factory.cpp b/src/core/web_event_factory.cpp
index f4940f305..f37cce6c7 100644
--- a/src/core/web_event_factory.cpp
+++ b/src/core/web_event_factory.cpp
@@ -1510,8 +1510,9 @@ blink::WebMouseWheelEvent WebEventFactory::toWebWheelEvent(QWheelEvent *ev)
webEvent.wheel_ticks_y = static_cast<float>(ev->angleDelta().y()) / QWheelEvent::DefaultDeltasPerStep;
webEvent.phase = toBlinkPhase(ev);
#if defined(Q_OS_DARWIN)
- // has_precise_scrolling_deltas is a macOS term meaning it is a system scroll gesture, see qnsview_mouse.mm
- webEvent.has_precise_scrolling_deltas = (ev->source() == Qt::MouseEventSynthesizedBySystem);
+ // PrecisePixel is a macOS term meaning it is a system scroll gesture, see qnsview_mouse.mm
+ if (ev->source() == Qt::MouseEventSynthesizedBySystem)
+ webEvent.delta_units = ui::input_types::ScrollGranularity::kScrollByPrecisePixel;
#endif
setBlinkWheelEventDelta(webEvent);
@@ -1528,7 +1529,8 @@ bool WebEventFactory::coalesceWebWheelEvent(blink::WebMouseWheelEvent &webEvent,
if (toBlinkPhase(ev) != webEvent.phase)
return false;
#if defined(Q_OS_DARWIN)
- if (webEvent.has_precise_scrolling_deltas != (ev->source() == Qt::MouseEventSynthesizedBySystem))
+ if ((webEvent.delta_units == ui::input_types::ScrollGranularity::kScrollByPrecisePixel)
+ != (ev->source() == Qt::MouseEventSynthesizedBySystem))
return false;
#endif
diff --git a/src/pdf/api/qpdfbookmarkmodel.h b/src/pdf/api/qpdfbookmarkmodel.h
new file mode 100644
index 000000000..8e06a1547
--- /dev/null
+++ b/src/pdf/api/qpdfbookmarkmodel.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFBOOKMARKMODEL_H
+#define QPDFBOOKMARKMODEL_H
+
+#include <QtPdf/qtpdfglobal.h>
+#include <QtCore/qabstractitemmodel.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocument;
+class QPdfBookmarkModelPrivate;
+
+class Q_PDF_EXPORT QPdfBookmarkModel : public QAbstractItemModel
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(StructureMode structureMode READ structureMode WRITE setStructureMode NOTIFY structureModeChanged)
+
+public:
+ enum StructureMode
+ {
+ TreeMode,
+ ListMode
+ };
+ Q_ENUM(StructureMode)
+
+ enum Role
+ {
+ TitleRole = Qt::DisplayRole,
+ LevelRole = Qt::UserRole,
+ PageNumberRole
+ };
+ Q_ENUM(Role)
+
+ explicit QPdfBookmarkModel(QObject *parent = nullptr);
+
+ QPdfDocument* document() const;
+ void setDocument(QPdfDocument *document);
+
+ StructureMode structureMode() const;
+ void setStructureMode(StructureMode mode);
+
+ QVariant data(const QModelIndex &index, int role) const override;
+ QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
+ QModelIndex parent(const QModelIndex &index) const override;
+ int rowCount(const QModelIndex &parent = QModelIndex()) const override;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const override;
+ QHash<int, QByteArray> roleNames() const override;
+
+Q_SIGNALS:
+ void documentChanged(QPdfDocument *document);
+ void structureModeChanged(QPdfBookmarkModel::StructureMode structureMode);
+
+private:
+ Q_DECLARE_PRIVATE(QPdfBookmarkModel)
+
+ Q_PRIVATE_SLOT(d_func(), void _q_documentStatusChanged())
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/pdf/api/qpdfdestination.h b/src/pdf/api/qpdfdestination.h
new file mode 100644
index 000000000..f9c186ff6
--- /dev/null
+++ b/src/pdf/api/qpdfdestination.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFDESTINATION_H
+#define QPDFDESTINATION_H
+
+#include <QtPdf/qtpdfglobal.h>
+#include <QtCore/qdebug.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qshareddata.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDestinationPrivate;
+
+class Q_PDF_EXPORT QPdfDestination
+{
+ Q_GADGET
+ Q_PROPERTY(bool valid READ isValid)
+ Q_PROPERTY(int page READ page)
+ Q_PROPERTY(QPointF location READ location)
+ Q_PROPERTY(qreal zoom READ zoom)
+
+public:
+ ~QPdfDestination();
+ QPdfDestination(const QPdfDestination &other);
+ QPdfDestination &operator=(const QPdfDestination &other);
+ QPdfDestination(QPdfDestination &&other) noexcept;
+ QPdfDestination &operator=(QPdfDestination &&other) noexcept { swap(other); return *this; }
+ void swap(QPdfDestination &other) noexcept { d.swap(other.d); }
+ bool isValid() const;
+ int page() const;
+ QPointF location() const;
+ qreal zoom() const;
+
+protected:
+ QPdfDestination();
+ QPdfDestination(int page, QPointF location, qreal zoom);
+ QPdfDestination(QPdfDestinationPrivate *d);
+ friend class QPdfDocument;
+ friend class QQuickPdfNavigationStack;
+
+protected:
+ QExplicitlySharedDataPointer<QPdfDestinationPrivate> d;
+};
+
+Q_PDF_EXPORT QDebug operator<<(QDebug, const QPdfDestination &);
+
+QT_END_NAMESPACE
+
+#endif // QPDFDESTINATION_H
diff --git a/src/pdf/api/qpdfdestination_p.h b/src/pdf/api/qpdfdestination_p.h
new file mode 100644
index 000000000..3520fb795
--- /dev/null
+++ b/src/pdf/api/qpdfdestination_p.h
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFDESTINATION_P_H
+#define QPDFDESTINATION_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 <QPointF>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDestinationPrivate : public QSharedData
+{
+public:
+ QPdfDestinationPrivate() = default;
+ QPdfDestinationPrivate(int page, QPointF location, qreal zoom)
+ : page(page),
+ location(location),
+ zoom(zoom) { }
+
+ int page = -1;
+ QPointF location;
+ qreal zoom = 1;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFDESTINATION_P_H
diff --git a/src/pdf/api/qpdfdocument.h b/src/pdf/api/qpdfdocument.h
new file mode 100644
index 000000000..f80a7832b
--- /dev/null
+++ b/src/pdf/api/qpdfdocument.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFDOCUMENT_H
+#define QPDFDOCUMENT_H
+
+#include <QtPdf/qtpdfglobal.h>
+
+#include <QtCore/qobject.h>
+#include <QtGui/qimage.h>
+#include <QtPdf/qpdfdocumentrenderoptions.h>
+#include <QtPdf/qpdfselection.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocumentPrivate;
+class QNetworkReply;
+
+class Q_PDF_EXPORT QPdfDocument : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL)
+ Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL)
+ Q_PROPERTY(Status status READ status NOTIFY statusChanged FINAL)
+
+public:
+ enum Status {
+ Null,
+ Loading,
+ Ready,
+ Unloading,
+ Error
+ };
+ Q_ENUM(Status)
+
+ enum DocumentError {
+ NoError,
+ UnknownError,
+ DataNotYetAvailableError,
+ FileNotFoundError,
+ InvalidFileFormatError,
+ IncorrectPasswordError,
+ UnsupportedSecuritySchemeError
+ };
+ Q_ENUM(DocumentError)
+
+ enum MetaDataField {
+ Title,
+ Subject,
+ Author,
+ Keywords,
+ Producer,
+ Creator,
+ CreationDate,
+ ModificationDate
+ };
+ Q_ENUM(MetaDataField)
+
+ explicit QPdfDocument(QObject *parent = nullptr);
+ ~QPdfDocument();
+
+ DocumentError load(const QString &fileName);
+
+ Status status() const;
+
+ void load(QIODevice *device);
+ void setPassword(const QString &password);
+ QString password() const;
+
+ QVariant metaData(MetaDataField field) const;
+
+ DocumentError error() const;
+
+ void close();
+
+ int pageCount() const;
+
+ QSizeF pageSize(int page) const;
+
+ QImage render(int page, QSize imageSize, QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions());
+
+ Q_INVOKABLE QPdfSelection getSelection(int page, QPointF start, QPointF end);
+ Q_INVOKABLE QPdfSelection getAllText(int page);
+
+Q_SIGNALS:
+ void passwordChanged();
+ void passwordRequired();
+ void statusChanged(QPdfDocument::Status status);
+ void pageCountChanged(int pageCount);
+
+private:
+ friend class QPdfBookmarkModelPrivate;
+ friend class QPdfLinkModelPrivate;
+ friend class QPdfSearchModel;
+ friend class QPdfSearchModelPrivate;
+
+ Q_PRIVATE_SLOT(d, void _q_tryLoadingWithSizeFromContentHeader())
+ Q_PRIVATE_SLOT(d, void _q_copyFromSequentialSourceDevice())
+ QScopedPointer<QPdfDocumentPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFDOCUMENT_H
diff --git a/src/pdf/api/qpdfdocument_p.h b/src/pdf/api/qpdfdocument_p.h
new file mode 100644
index 000000000..b69b6f19e
--- /dev/null
+++ b/src/pdf/api/qpdfdocument_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFDOCUMENT_P_H
+#define QPDFDOCUMENT_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 "qpdfdocument.h"
+
+#include "third_party/pdfium/public/fpdfview.h"
+#include "third_party/pdfium/public/fpdf_dataavail.h"
+
+#include <QtCore/qbuffer.h>
+#include <QtCore/qmutex.h>
+#include <QtCore/qpointer.h>
+#include <QtNetwork/qnetworkreply.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfMutexLocker : public QMutexLocker
+{
+public:
+ QPdfMutexLocker();
+};
+
+class QPdfDocumentPrivate: public FPDF_FILEACCESS, public FX_FILEAVAIL, public FX_DOWNLOADHINTS
+{
+public:
+ QPdfDocumentPrivate();
+ ~QPdfDocumentPrivate();
+
+ QPdfDocument *q;
+
+ FPDF_AVAIL avail;
+ FPDF_DOCUMENT doc;
+ bool loadComplete;
+
+ QPointer<QIODevice> device;
+ QScopedPointer<QIODevice> ownDevice;
+ QBuffer asyncBuffer;
+ QPointer<QIODevice> sequentialSourceDevice;
+ QByteArray password;
+
+ QPdfDocument::Status status;
+ QPdfDocument::DocumentError lastError;
+ int pageCount;
+
+ void clear();
+
+ void load(QIODevice *device, bool ownDevice);
+ void loadAsync(QIODevice *device);
+
+ void _q_tryLoadingWithSizeFromContentHeader();
+ void initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize);
+ void _q_copyFromSequentialSourceDevice();
+ void tryLoadDocument();
+ void checkComplete();
+ bool checkPageComplete(int page);
+ void setStatus(QPdfDocument::Status status);
+
+ static FPDF_BOOL fpdf_IsDataAvail(struct _FX_FILEAVAIL* pThis, size_t offset, size_t size);
+ 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);
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFDOCUMENT_P_H
diff --git a/src/pdf/api/qpdfdocumentrenderoptions.h b/src/pdf/api/qpdfdocumentrenderoptions.h
new file mode 100644
index 000000000..cafb4716f
--- /dev/null
+++ b/src/pdf/api/qpdfdocumentrenderoptions.h
@@ -0,0 +1,94 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFDOCUMENTRENDEROPTIONS_H
+#define QPDFDOCUMENTRENDEROPTIONS_H
+
+#include <QtPdf/qpdfnamespace.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qrect.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocumentRenderOptions
+{
+public:
+ Q_DECL_CONSTEXPR QPdfDocumentRenderOptions() noexcept : m_renderFlags(0), m_rotation(0), m_reserved(0) {}
+
+ Q_DECL_CONSTEXPR QPdf::Rotation rotation() const noexcept { return static_cast<QPdf::Rotation>(m_rotation); }
+ Q_DECL_RELAXED_CONSTEXPR void setRotation(QPdf::Rotation r) noexcept { m_rotation = r; }
+
+ Q_DECL_CONSTEXPR QPdf::RenderFlags renderFlags() const noexcept { return static_cast<QPdf::RenderFlags>(m_renderFlags); }
+ Q_DECL_RELAXED_CONSTEXPR void setRenderFlags(QPdf::RenderFlags r) noexcept { m_renderFlags = r; }
+
+ Q_DECL_CONSTEXPR QRect scaledClipRect() const noexcept { return m_clipRect; }
+ Q_DECL_RELAXED_CONSTEXPR void setScaledClipRect(const QRect &r) noexcept { m_clipRect = r; }
+
+ Q_DECL_CONSTEXPR QSize scaledSize() const noexcept { return m_scaledSize; }
+ Q_DECL_RELAXED_CONSTEXPR void setScaledSize(const QSize &s) noexcept { m_scaledSize = s; }
+
+private:
+ friend Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept;
+
+ QRect m_clipRect;
+ QSize m_scaledSize;
+
+ quint32 m_renderFlags : 8;
+ quint32 m_rotation : 3;
+ quint32 m_reserved : 21;
+ quint32 m_reserved2 = 0;
+};
+
+Q_DECLARE_TYPEINFO(QPdfDocumentRenderOptions, Q_PRIMITIVE_TYPE);
+
+Q_DECL_CONSTEXPR inline bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept
+{
+ return lhs.m_clipRect == rhs.m_clipRect && lhs.m_scaledSize == rhs.m_scaledSize &&
+ lhs.m_renderFlags == rhs.m_renderFlags && lhs.m_rotation == rhs.m_rotation &&
+ lhs.m_reserved == rhs.m_reserved && lhs.m_reserved2 == rhs.m_reserved2; // fix -Wunused-private-field
+}
+
+Q_DECL_CONSTEXPR inline bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs) noexcept
+{
+ return !operator==(lhs, rhs);
+}
+
+QT_END_NAMESPACE
+
+Q_DECLARE_METATYPE(QPdfDocumentRenderOptions)
+
+#endif // QPDFDOCUMENTRENDEROPTIONS_H
diff --git a/src/pdf/api/qpdflinkmodel_p.h b/src/pdf/api/qpdflinkmodel_p.h
new file mode 100644
index 000000000..cf9c0aad4
--- /dev/null
+++ b/src/pdf/api/qpdflinkmodel_p.h
@@ -0,0 +1,106 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFLINKMODEL_P_H
+#define QPDFLINKMODEL_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 "qtpdfglobal.h"
+#include "qpdfdocument.h"
+
+#include <QObject>
+#include <QAbstractListModel>
+
+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 : int {
+ Rect = Qt::UserRole,
+ Url,
+ Page,
+ Location,
+ Zoom,
+ _Count
+ };
+ 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);
+
+private Q_SLOTS:
+ void onStatusChanged(QPdfDocument::Status status);
+
+private:
+ QHash<int, QByteArray> m_roleNames;
+ Q_DECLARE_PRIVATE(QPdfLinkModel)
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFLINKMODEL_P_H
diff --git a/src/pdf/api/qpdflinkmodel_p_p.h b/src/pdf/api/qpdflinkmodel_p_p.h
new file mode 100644
index 000000000..3e44f1651
--- /dev/null
+++ b/src/pdf/api/qpdflinkmodel_p_p.h
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#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 <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();
+
+ struct Link {
+ // where it is on the current page
+ QRectF rect;
+ int textStart = -1;
+ int textCharCount = 0;
+ // destination inside PDF
+ int page = -1; // -1 means look at the url instead
+ QPointF location;
+ qreal zoom = 1;
+ // web destination
+ QUrl url;
+
+ QString toString() const;
+ };
+
+ QPdfDocument *document = nullptr;
+ QVector<Link> links;
+ int page = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFLINKMODEL_P_P_H
diff --git a/src/pdf/api/qpdfnamespace.h b/src/pdf/api/qpdfnamespace.h
new file mode 100644
index 000000000..e76d0abd9
--- /dev/null
+++ b/src/pdf/api/qpdfnamespace.h
@@ -0,0 +1,73 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFNAMESPACE_H
+#define QPDFNAMESPACE_H
+
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace QPdf {
+ Q_NAMESPACE
+
+ enum Rotation {
+ Rotate0,
+ Rotate90,
+ Rotate180,
+ Rotate270
+ };
+ Q_ENUM_NS(Rotation)
+
+ enum RenderFlag {
+ NoRenderFlags = 0x000,
+ RenderAnnotations = 0x001,
+ RenderOptimizedForLcd = 0x002,
+ RenderGrayscale = 0x004,
+ RenderForceHalftone = 0x008,
+ RenderTextAliased = 0x010,
+ RenderImageAliased = 0x020,
+ RenderPathAliased = 0x040
+ };
+ Q_FLAG_NS(RenderFlag)
+ Q_DECLARE_FLAGS(RenderFlags, RenderFlag)
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QPdf::RenderFlags)
+
+QT_END_NAMESPACE
+#endif
diff --git a/src/pdf/api/qpdfpagenavigation.h b/src/pdf/api/qpdfpagenavigation.h
new file mode 100644
index 000000000..0f416bf77
--- /dev/null
+++ b/src/pdf/api/qpdfpagenavigation.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFPAGENAVIGATION_H
+#define QPDFPAGENAVIGATION_H
+
+#include <QtPdf/qtpdfglobal.h>
+#include <QtCore/qobject.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocument;
+class QPdfPageNavigationPrivate;
+
+class Q_PDF_EXPORT QPdfPageNavigation : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged)
+
+ Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
+ Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged)
+ Q_PROPERTY(bool canGoToPreviousPage READ canGoToPreviousPage NOTIFY canGoToPreviousPageChanged)
+ Q_PROPERTY(bool canGoToNextPage READ canGoToNextPage NOTIFY canGoToNextPageChanged)
+
+public:
+ explicit QPdfPageNavigation(QObject *parent = nullptr);
+ ~QPdfPageNavigation();
+
+ QPdfDocument* document() const;
+ void setDocument(QPdfDocument *document);
+
+ int currentPage() const;
+ void setCurrentPage(int currentPage);
+
+ int pageCount() const;
+
+ bool canGoToPreviousPage() const;
+ bool canGoToNextPage() const;
+
+public Q_SLOTS:
+ void goToPreviousPage();
+ void goToNextPage();
+
+Q_SIGNALS:
+ void documentChanged(QPdfDocument *document);
+ void currentPageChanged(int currentPage);
+ void pageCountChanged(int pageCount);
+ void canGoToPreviousPageChanged(bool canGo);
+ void canGoToNextPageChanged(bool canGo);
+
+private:
+ Q_DECLARE_PRIVATE(QPdfPageNavigation)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/pdf/api/qpdfpagerenderer.h b/src/pdf/api/qpdfpagerenderer.h
new file mode 100644
index 000000000..c7b8de0df
--- /dev/null
+++ b/src/pdf/api/qpdfpagerenderer.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFPAGERENDERER_H
+#define QPDFPAGERENDERER_H
+
+#include <QtPdf/qtpdfglobal.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qsize.h>
+#include <QtPdf/qpdfdocumentrenderoptions.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocument;
+class QPdfPageRendererPrivate;
+
+class Q_PDF_EXPORT QPdfPageRenderer : public QObject
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(RenderMode renderMode READ renderMode WRITE setRenderMode NOTIFY renderModeChanged)
+
+public:
+ enum class RenderMode
+ {
+ MultiThreaded,
+ SingleThreaded
+ };
+ Q_ENUM(RenderMode)
+
+ explicit QPdfPageRenderer(QObject *parent = nullptr);
+ ~QPdfPageRenderer() override;
+
+ RenderMode renderMode() const;
+ void setRenderMode(RenderMode mode);
+
+ QPdfDocument* document() const;
+ void setDocument(QPdfDocument *document);
+
+ quint64 requestPage(int pageNumber, QSize imageSize,
+ QPdfDocumentRenderOptions options = QPdfDocumentRenderOptions());
+
+Q_SIGNALS:
+ void documentChanged(QPdfDocument *document);
+ void renderModeChanged(RenderMode renderMode);
+
+ void pageRendered(int pageNumber, QSize imageSize, const QImage &image,
+ QPdfDocumentRenderOptions options, quint64 requestId);
+
+private:
+ Q_DECLARE_PRIVATE(QPdfPageRenderer)
+};
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/pdf/api/qpdfsearchmodel.h b/src/pdf/api/qpdfsearchmodel.h
new file mode 100644
index 000000000..eb0fb831f
--- /dev/null
+++ b/src/pdf/api/qpdfsearchmodel.h
@@ -0,0 +1,98 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFSEARCHMODEL_H
+#define QPDFSEARCHMODEL_H
+
+#include <QtPdf/qtpdfglobal.h>
+
+#include <QtCore/qabstractitemmodel.h>
+#include <QtPdf/qpdfdocument.h>
+#include <QtPdf/qpdfsearchresult.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfSearchModelPrivate;
+
+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)
+
+public:
+ enum class Role : int {
+ Page = Qt::UserRole,
+ IndexOnPage,
+ Location,
+ ContextBefore,
+ ContextAfter,
+ _Count
+ };
+ Q_ENUM(Role)
+ explicit QPdfSearchModel(QObject *parent = nullptr);
+ ~QPdfSearchModel();
+
+ QVector<QPdfSearchResult> resultsOnPage(int page) const;
+ QPdfSearchResult resultAtIndex(int index) const;
+
+ QPdfDocument *document() const;
+ QString searchString() const;
+
+ QHash<int, QByteArray> roleNames() const override;
+ int rowCount(const QModelIndex &parent) const override;
+ QVariant data(const QModelIndex &index, int role) const override;
+
+public Q_SLOTS:
+ void setSearchString(QString searchString);
+ void setDocument(QPdfDocument *document);
+
+Q_SIGNALS:
+ void documentChanged();
+ void searchStringChanged();
+
+protected:
+ void updatePage(int page);
+ void timerEvent(QTimerEvent *event) override;
+
+private:
+ QHash<int, QByteArray> m_roleNames;
+ Q_DECLARE_PRIVATE(QPdfSearchModel)
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFSEARCHMODEL_H
diff --git a/src/pdf/api/qpdfsearchmodel_p.h b/src/pdf/api/qpdfsearchmodel_p.h
new file mode 100644
index 000000000..2a23706b2
--- /dev/null
+++ b/src/pdf/api/qpdfsearchmodel_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFSEARCHMODEL_P_H
+#define QPDFSEARCHMODEL_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 "qpdfsearchmodel.h"
+#include "qpdfsearchresult_p.h"
+#include <private/qabstractitemmodel_p.h>
+
+#include "third_party/pdfium/public/fpdfview.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPdfSearchModelPrivate : public QAbstractItemModelPrivate
+{
+ Q_DECLARE_PUBLIC(QPdfSearchModel)
+
+public:
+ QPdfSearchModelPrivate();
+ void clearResults();
+ bool doSearch(int page);
+
+ struct PageAndIndex {
+ int page;
+ int index;
+ };
+ PageAndIndex pageAndIndexForResult(int resultIndex);
+ int rowsBeforePage(int page);
+
+ QPdfDocument *document = nullptr;
+ QString searchString;
+ QVector<bool> pagesSearched;
+ QVector<QVector<QPdfSearchResult>> searchResults;
+ int rowCountSoFar = 0;
+ int updateTimerId = -1;
+ int nextPageToUpdate = 0;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFSEARCHMODEL_P_H
diff --git a/src/pdf/api/qpdfsearchresult.h b/src/pdf/api/qpdfsearchresult.h
new file mode 100644
index 000000000..2dfca2dc4
--- /dev/null
+++ b/src/pdf/api/qpdfsearchresult.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFSEARCHRESULT_H
+#define QPDFSEARCHRESULT_H
+
+#include <QtCore/qdebug.h>
+#include <QtCore/qrect.h>
+#include <QtCore/qvector.h>
+#include <QtPdf/qpdfdestination.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfSearchResultPrivate;
+
+class Q_PDF_EXPORT QPdfSearchResult : public QPdfDestination
+{
+ Q_GADGET
+ Q_PROPERTY(QString contextBefore READ contextBefore)
+ Q_PROPERTY(QString contextAfter READ contextAfter)
+ Q_PROPERTY(QVector<QRectF> rectangles READ rectangles)
+
+public:
+ QPdfSearchResult();
+ ~QPdfSearchResult() {}
+
+ QString contextBefore() const;
+ QString contextAfter() const;
+ QVector<QRectF> rectangles() const;
+
+private:
+ QPdfSearchResult(int page, QVector<QRectF> rects, QString contextBefore, QString contextAfter);
+ QPdfSearchResult(QPdfSearchResultPrivate *d);
+ friend class QPdfDocument;
+ friend class QPdfSearchModelPrivate;
+ friend class QQuickPdfNavigationStack;
+};
+
+Q_PDF_EXPORT QDebug operator<<(QDebug, const QPdfSearchResult &);
+
+QT_END_NAMESPACE
+
+#endif // QPDFSEARCHRESULT_H
diff --git a/src/pdf/api/qpdfsearchresult_p.h b/src/pdf/api/qpdfsearchresult_p.h
new file mode 100644
index 000000000..615dce4e0
--- /dev/null
+++ b/src/pdf/api/qpdfsearchresult_p.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFSEARCHRESULT_P_H
+#define QPDFSEARCHRESULT_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 "qpdfdestination_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPdfSearchResultPrivate : public QPdfDestinationPrivate
+{
+public:
+ QPdfSearchResultPrivate() = default;
+ QPdfSearchResultPrivate(int page, QVector<QRectF> rects, QString contextBefore, QString contextAfter) :
+ QPdfDestinationPrivate(page, rects.first().topLeft(), 0),
+ contextBefore(contextBefore),
+ contextAfter(contextAfter),
+ rects(rects) {}
+
+ QString contextBefore;
+ QString contextAfter;
+ QVector<QRectF> rects;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFSEARCHRESULT_P_H
diff --git a/src/pdf/api/qpdfselection.h b/src/pdf/api/qpdfselection.h
new file mode 100644
index 000000000..5a6a1cddc
--- /dev/null
+++ b/src/pdf/api/qpdfselection.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFSELECTION_H
+#define QPDFSELECTION_H
+
+#include <QtPdf/qtpdfglobal.h>
+
+#include <QtCore/qobject.h>
+#include <QtCore/qshareddata.h>
+#include <QtGui/qclipboard.h>
+#include <QtGui/qpolygon.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfSelectionPrivate;
+
+class Q_PDF_EXPORT QPdfSelection
+{
+ Q_GADGET
+ Q_PROPERTY(bool valid READ isValid)
+ Q_PROPERTY(QVector<QPolygonF> bounds READ bounds)
+ Q_PROPERTY(QString text READ text)
+
+public:
+ ~QPdfSelection();
+ QPdfSelection(const QPdfSelection &other);
+ QPdfSelection &operator=(const QPdfSelection &other);
+ QPdfSelection(QPdfSelection &&other) noexcept;
+ QPdfSelection &operator=(QPdfSelection &&other) noexcept { swap(other); return *this; }
+ void swap(QPdfSelection &other) noexcept { d.swap(other.d); }
+ bool isValid() const;
+ QVector<QPolygonF> bounds() const;
+ QString text() const;
+#if QT_CONFIG(clipboard)
+ void copyToClipboard(QClipboard::Mode mode = QClipboard::Clipboard) const;
+#endif
+
+private:
+ QPdfSelection();
+ QPdfSelection(const QString &text, QVector<QPolygonF> bounds);
+ QPdfSelection(QPdfSelectionPrivate *d);
+ friend class QPdfDocument;
+ friend class QQuickPdfSelection;
+
+private:
+ QExplicitlySharedDataPointer<QPdfSelectionPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFSELECTION_H
diff --git a/src/pdf/api/qpdfselection_p.h b/src/pdf/api/qpdfselection_p.h
new file mode 100644
index 000000000..37145f7f9
--- /dev/null
+++ b/src/pdf/api/qpdfselection_p.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFSELECTION_P_H
+#define QPDFSELECTION_P_H
+
+#include <QPolygonF>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfSelectionPrivate : public QSharedData
+{
+public:
+ QPdfSelectionPrivate() = default;
+ QPdfSelectionPrivate(const QString &text, QVector<QPolygonF> bounds)
+ : text(text),
+ bounds(bounds) { }
+
+ QString text;
+ QVector<QPolygonF> bounds;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFSELECTION_P_H
diff --git a/src/pdf/api/qtpdfglobal.h b/src/pdf/api/qtpdfglobal.h
new file mode 100644
index 000000000..223ec4bcb
--- /dev/null
+++ b/src/pdf/api/qtpdfglobal.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTPDFGLOBAL_H
+#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
+
+QT_END_NAMESPACE
+
+#endif // QTPDFGLOBAL_H
+
diff --git a/src/pdf/configure.json b/src/pdf/configure.json
new file mode 100644
index 000000000..ddc0e99dc
--- /dev/null
+++ b/src/pdf/configure.json
@@ -0,0 +1,64 @@
+{
+ "module": "pdf",
+ "depends" : [ "buildtools-private" ],
+ "testDir": "../../config.tests",
+ "condition": "features.build-qtpdf && features.webengine-qtpdf-support",
+ "libraries": {
+ },
+ "tests": {
+ },
+ "features": {
+ "pdf-v8": {
+ "label": "Support V8",
+ "purpose": "Enables javascript support.",
+ "autoDetect": "false",
+ "condition": "!config.ios",
+ "output": ["privateFeature" ]
+ },
+ "pdf-xfa": {
+ "label": "Support XFA",
+ "purpose": "Enables XFA support.",
+ "condition": "features.pdf-v8",
+ "output": ["privateFeature" ]
+ },
+ "pdf-xfa-bmp": {
+ "label": "Support XFA-BMP",
+ "purpose": "Enables XFA-BMP support.",
+ "condition": "features.pdf-xfa",
+ "output": ["privateFeature" ]
+ },
+ "pdf-xfa-gif": {
+ "label": "Support XFA-GIF",
+ "purpose": "Enables XFA-GIF support.",
+ "condition": "features.pdf-xfa",
+ "output": ["privateFeature" ]
+ },
+ "pdf-xfa-png": {
+ "label": "Support XFA-PNG",
+ "purpose": "Enables XFA-PNG support.",
+ "condition": "features.pdf-xfa",
+ "output": ["privateFeature" ]
+ },
+ "pdf-xfa-tiff": {
+ "label": "Support XFA-TIFF",
+ "purpose": "Enables XFA-TIFF support.",
+ "condition": "features.pdf-xfa",
+ "output": ["privateFeature" ]
+ }
+ },
+ "report": [
+ ],
+ "summary": [
+ {
+ "section": "Qt PDF",
+ "entries": [
+ "pdf-v8",
+ "pdf-xfa",
+ "pdf-xfa-bmp",
+ "pdf-xfa-gif",
+ "pdf-xfa-png",
+ "pdf-xfa-tiff"
+ ]
+ }
+ ]
+}
diff --git a/src/pdf/doc/qtpdf.qdocconf b/src/pdf/doc/qtpdf.qdocconf
new file mode 100644
index 000000000..7a77105c9
--- /dev/null
+++ b/src/pdf/doc/qtpdf.qdocconf
@@ -0,0 +1,58 @@
+include($QT_INSTALL_DOCS/global/qt-module-defaults.qdocconf)
+
+project = QtPdf
+description = Qt Pdf Reference Documentation
+version = $QT_VERSION
+
+qhp.projects = QtPdf
+
+qhp.QtPdf.file = qtpdf.qhp
+qhp.QtPdf.namespace = org.qt-project.qtpdf.$QT_VERSION_TAG
+qhp.QtPdf.virtualFolder = qtpdf
+qhp.QtPdf.indexTitle = Qt PDF
+qhp.QtPdf.indexRoot =
+
+qhp.QtPdf.filterAttributes = qtpdf $QT_VERSION qtrefdoc
+qhp.QtPdf.customFilters.Qt.name = QtPdf $QT_VERSION
+qhp.QtPdf.customFilters.Qt.filterAttributes = qtpdf $QT_VERSION
+
+qhp.QtPdf.subprojects = classes qmltypes examples
+
+qhp.QtPdf.subprojects.classes.title = C++ Classes
+qhp.QtPdf.subprojects.classes.indexTitle = Qt PDF C++ Classes
+qhp.QtPdf.subprojects.classes.selectors = class fake:headerfile
+qhp.QtPdf.subprojects.classes.sortPages = true
+
+qhp.QtPdf.subprojects.qmltypes.title = QML Types
+qhp.QtPdf.subprojects.qmltypes.indexTitle = Qt Quick PDF QML Types
+qhp.QtPdf.subprojects.qmltypes.selectors = qmltype
+qhp.QtPdf.subprojects.qmltypes.sortPages = true
+
+qhp.QtPdf.subprojects.examples.title = Examples
+qhp.QtPdf.subprojects.examples.indexTitle = Qt PDF Examples
+qhp.QtPdf.subprojects.examples.selectors = doc:example
+qhp.QtPdf.subprojects.examples.sortPages = true
+
+depends += qtcore \
+ qtwidgets \
+ qtgui \
+ qtdoc \
+ qmake \
+ qtdesigner \
+ qtquick \
+ qtcmake
+
+headerdirs += ../api \
+ ../quick
+
+sourcedirs += .. \
+ ../quick
+
+exampledirs += ../../../examples/pdfwidgets \
+ snippets/
+
+imagedirs += images
+
+navigation.landingpage = "Qt PDF"
+navigation.cppclassespage = "Qt PDF C++ Classes"
+navigation.qmltypespage = "Qt WebEngine QML Types"
diff --git a/src/pdf/doc/snippets/qtpdf-build.cmake b/src/pdf/doc/snippets/qtpdf-build.cmake
new file mode 100644
index 000000000..d46b9c3ee
--- /dev/null
+++ b/src/pdf/doc/snippets/qtpdf-build.cmake
@@ -0,0 +1,2 @@
+find_package(Qt5 COMPONENTS Pdf REQUIRED)
+target_link_libraries(mytarget Qt5::Pdf)
diff --git a/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc b/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc
new file mode 100644
index 000000000..25593b1ee
--- /dev/null
+++ b/src/pdf/doc/snippets/qtpdf_build_snippet.qdoc
@@ -0,0 +1,35 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+//! [0]
+QT += pdf
+//! [0]
+
+
+//! [1]
+#include <QtPdf>
+//! [1]
diff --git a/src/pdf/doc/src/qtpdf-examples.qdoc b/src/pdf/doc/src/qtpdf-examples.qdoc
new file mode 100644
index 000000000..9daa0e7f8
--- /dev/null
+++ b/src/pdf/doc/src/qtpdf-examples.qdoc
@@ -0,0 +1,37 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \group qtpdf-examples
+ \ingroup all-examples
+
+ \title Qt PDF Examples
+ \brief Using the classes and types in the Qt PDF module.
+
+ The following examples illustrate how to use the C++ classes and QML types
+ in the \l{Qt PDF} module to render PDF documents.
+*/
diff --git a/src/pdf/doc/src/qtpdf-index.qdoc b/src/pdf/doc/src/qtpdf-index.qdoc
new file mode 100644
index 000000000..b32787eb5
--- /dev/null
+++ b/src/pdf/doc/src/qtpdf-index.qdoc
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \page qtpdf-index.html
+ \title Qt PDF
+
+ \brief Renders pages from PDF documents.
+
+ The Qt PDF module contains classes and functions for rendering
+ PDF documents. The \l QPdfDocument class loads a PDF document
+ and renders pages from it according to the options provided by
+ the \l QPdfDocumentRenderOptions class. The \l QPdfPageRenderer
+ class manages a queue that collects all render requests. The
+ \l QPdfPageNavigation class handles the navigation through a
+ PDF document.
+
+ \include module-use.qdocinc using qt module
+ \quotefile qtpdf-build.cmake
+
+ See also the \l{Build with CMake} overview.
+
+ \section2 Building with qmake
+
+ To include the definitions of the module's classes, use the
+ following directive:
+
+ \snippet qtpdf_build_snippet.qdoc 1
+
+ To link against the module, add this line to your qmake project file:
+
+ \snippet qtpdf_build_snippet.qdoc 0
+
+ \section1 Articles and Guides
+
+ \list
+ \li \l{Qt PDF Overview}
+ \endlist
+
+ \section1 Examples
+
+ \list
+ \li \l{Qt PDF Examples}
+ \endlist
+
+ \section1 API Reference
+
+ \list
+ \li \l{Qt PDF C++ Classes}
+ \li \l{Qt Quick PDF QML Types}
+ \endlist
+*/
diff --git a/src/pdf/doc/src/qtpdf-module.qdoc b/src/pdf/doc/src/qtpdf-module.qdoc
new file mode 100644
index 000000000..4170deb38
--- /dev/null
+++ b/src/pdf/doc/src/qtpdf-module.qdoc
@@ -0,0 +1,50 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU Free Documentation License Usage
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of
+** this file. Please review the following information to ensure
+** the GNU Free Documentation License version 1.3 requirements
+** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+/*!
+ \module QtPdf
+ \title Qt PDF C++ Classes
+ \brief Renders pages from PDF documents.
+ \since 5.14
+ \ingroup qtwebengine-modules
+ \ingroup modules
+
+ The Qt PDF module contains classes and functions for rendering
+ PDF documents.
+
+ To include the definitions of the module's classes, use the
+ following directive:
+
+ \snippet qtpdf_build_snippet.qdoc 1
+
+ \if !defined(qtforpython)
+ To link against the module, add this line to your qmake project file:
+
+ \snippet qtpdf_build_snippet.qdoc 0
+ \endif
+*/
diff --git a/src/pdf/gn_run.pro b/src/pdf/gn_run.pro
new file mode 100644
index 000000000..7fd4d4ffc
--- /dev/null
+++ b/src/pdf/gn_run.pro
@@ -0,0 +1,70 @@
+include($$QTWEBENGINE_OUT_ROOT/src/buildtools/qtbuildtools-config.pri)
+QT_FOR_CONFIG += buildtools-private
+
+TEMPLATE = aux
+
+qtConfig(debug_and_release): CONFIG += debug_and_release build_all
+
+qtConfig(webengine-system-ninja) {
+ QT_TOOL.ninja.binary = ninja
+} else {
+ QT_TOOL.ninja.binary = $$shell_quote($$shell_path($$ninjaPath()))
+}
+
+win32 {
+ # Add the gnuwin32/bin subdir of qt5.git to PATH. Needed for calling bison and friends.
+ gnuwin32path.name = PATH
+ gnuwin32path.value = $$shell_path($$clean_path($$QTWEBENGINE_ROOT/../gnuwin32/bin))
+ gnuwin32path.CONFIG += prepend
+ exists($$gnuwin32path.value): QT_TOOL_ENV = gnuwin32path
+}
+
+qtPrepareTool(NINJA, ninja)
+QT_TOOL_ENV =
+
+build_pass|!debug_and_release {
+ gn_binary = gn
+
+ runninja.target = run_ninja
+
+ # fixme: refine args
+ gn_args = $$gnArgs()
+
+ include($$QTWEBENGINE_ROOT/src/buildtools/config/pdf.pri)
+
+ # fixme: qtwebengine_target
+ gn_args += "qtwebengine_target=\"$$system_path($$OUT_PWD/$$getConfigDir()):QtPdf\""
+
+ # fixme:
+ !qtConfig(webengine-system-gn) {
+ gn_binary = $$system_quote($$system_path($$gnPath()))
+ }
+
+ gn_args = $$system_quote($$gn_args)
+ gn_src_root = $$system_quote($$system_path($$QTWEBENGINE_ROOT/$$getChromiumSrcDir()))
+ gn_build_root = $$system_quote($$system_path($$OUT_PWD/$$getConfigDir()))
+ gn_python = "--script-executable=$$pythonPathForSystem()"
+ gn_run = $$gn_binary gen $$gn_build_root $$gn_python --args=$$gn_args --root=$$gn_src_root
+
+ message("Running: $$gn_run ")
+ !system($$gn_run) {
+ error("GN run error!")
+ }
+
+ ninjaflags = $$(NINJAFLAGS)
+ isEmpty(ninjaflags):!silent: ninjaflags = "-v"
+
+ runninja.commands = $$NINJA $$ninjaflags -C $$gn_build_root QtPdf
+ QMAKE_EXTRA_TARGETS += runninja
+
+ build_pass:build_all: default_target.target = all
+ else: default_target.target = first
+ default_target.depends = runninja
+ QMAKE_EXTRA_TARGETS += default_target
+}
+
+!build_pass:debug_and_release {
+ # Special GNU make target for the meta Makefile that ensures that our debug and release Makefiles won't both run ninja in parallel.
+ notParallel.target = .NOTPARALLEL
+ QMAKE_EXTRA_TARGETS += notParallel
+}
diff --git a/src/pdf/jsbridge.cpp b/src/pdf/jsbridge.cpp
new file mode 100644
index 000000000..33d3b2465
--- /dev/null
+++ b/src/pdf/jsbridge.cpp
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "fpdfsdk/javascript/JS_Runtime_Stub.cpp"
+
diff --git a/src/pdf/pdf.pro b/src/pdf/pdf.pro
new file mode 100644
index 000000000..c5513ce93
--- /dev/null
+++ b/src/pdf/pdf.pro
@@ -0,0 +1,16 @@
+TEMPLATE = subdirs
+pdfcore.file = pdfcore.pro
+pdfcore_generator.file = pdfcore_generator.pro
+gn_run.file = gn_run.pro
+
+gn_run.depends = pdfcore_generator
+pdfcore.depends = gn_run
+quick.depends = pdfcore
+
+SUBDIRS += \
+ pdfcore_generator \
+ gn_run \
+ pdfcore \
+ quick
+
+
diff --git a/src/pdf/pdfcore.pro b/src/pdf/pdfcore.pro
new file mode 100644
index 000000000..c87722b7e
--- /dev/null
+++ b/src/pdf/pdfcore.pro
@@ -0,0 +1,93 @@
+TARGET = QtPdf
+MODULE = pdf
+
+QT += gui core core-private
+QT_PRIVATE += network
+
+TEMPLATE = lib
+
+INCLUDEPATH += $$QTWEBENGINE_ROOT/src/pdf
+CHROMIUM_SRC_DIR = $$QTWEBENGINE_ROOT/$$getChromiumSrcDir()
+CHROMIUM_GEN_DIR = $$OUT_PWD/../$$getConfigDir()/gen
+INCLUDEPATH += $$QTWEBENGINE_ROOT/src/pdf \
+ $$CHROMIUM_GEN_DIR \
+ $$CHROMIUM_SRC_DIR \
+ api
+
+DEFINES += QT_BUILD_PDF_LIB
+win32: DEFINES += NOMINMAX
+
+linking_pri = $$OUT_PWD/$$getConfigDir()/$${TARGET}.pri
+!include($$linking_pri) {
+ error("Could not find the linking information that gn should have generated.")
+}
+
+isEmpty(NINJA_OBJECTS): error("Missing object files from QtPdf linking pri.")
+isEmpty(NINJA_LFLAGS): error("Missing linker flags from QtPdf linking pri")
+isEmpty(NINJA_LIBS): error("Missing library files from QtPdf linking pri")
+
+NINJA_OBJECTS = $$eval($$list($$NINJA_OBJECTS))
+RSP_FILE = $$OUT_PWD/$$getConfigDir()/$${TARGET}.rsp
+for(object, NINJA_OBJECTS): RSP_CONTENT += $$object
+write_file($$RSP_FILE, RSP_CONTENT)
+
+macos:LIBS_PRIVATE += -Wl,-filelist,$$shell_quote($$RSP_FILE)
+linux:LIBS_PRIVATE += @$$RSP_FILE
+
+# QTBUG-58710 add main rsp file on windows
+win32:QMAKE_LFLAGS += @$$RSP_FILE
+
+!isEmpty(NINJA_ARCHIVES) {
+ linux: LIBS_PRIVATE += -Wl,--start-group $$NINJA_ARCHIVES -Wl,--end-group
+ else: LIBS_PRIVATE += $$NINJA_ARCHIVES
+}
+
+LIBS_PRIVATE += $$NINJA_LIB_DIRS $$NINJA_LIBS
+
+QMAKE_DOCS = $$PWD/doc/qtpdf.qdocconf
+
+gcc {
+ QMAKE_CXXFLAGS_WARN_ON += -Wno-unused-parameter
+}
+
+msvc {
+ QMAKE_CXXFLAGS_WARN_ON += -wd"4100"
+}
+
+ios: OBJECTS += $$NINJA_OBJECTS
+
+SOURCES += \
+ qpdfbookmarkmodel.cpp \
+ qpdfdestination.cpp \
+ qpdfdocument.cpp \
+ qpdflinkmodel.cpp \
+ qpdfpagenavigation.cpp \
+ qpdfpagerenderer.cpp \
+ qpdfsearchmodel.cpp \
+ qpdfsearchresult.cpp \
+ qpdfselection.cpp \
+
+# all "public" headers must be in "api" for sync script and to hide auto generated headers
+# by Chromium in case of in-source build
+
+HEADERS += \
+ api/qpdfbookmarkmodel.h \
+ api/qpdfdestination.h \
+ api/qpdfdestination_p.h \
+ api/qpdfdocument.h \
+ api/qpdfdocument_p.h \
+ api/qpdfdocumentrenderoptions.h \
+ api/qtpdfglobal.h \
+ api/qpdflinkmodel_p.h \
+ api/qpdflinkmodel_p_p.h \
+ api/qpdfnamespace.h \
+ api/qpdfpagenavigation.h \
+ api/qpdfpagerenderer.h \
+ api/qpdfsearchmodel.h \
+ api/qpdfsearchmodel_p.h \
+ api/qpdfsearchresult.h \
+ api/qpdfsearchresult_p.h \
+ api/qpdfselection.h \
+ api/qpdfselection_p.h \
+
+load(qt_module)
diff --git a/src/pdf/pdfcore_generator.pro b/src/pdf/pdfcore_generator.pro
new file mode 100644
index 000000000..c8eb13b81
--- /dev/null
+++ b/src/pdf/pdfcore_generator.pro
@@ -0,0 +1,15 @@
+qtConfig(debug_and_release): CONFIG += debug_and_release
+
+TARGET = QtPdf
+TEMPLATE = lib
+CONFIG = gn_generator $$CONFIG
+ios: CONFIG -=static # note we still do static on ios when linking
+GN_SRC_DIR = $$PWD
+GN_FILE = $$OUT_PWD/$$getConfigDir()/BUILD.gn
+GN_FIND_MOCABLES_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_find_mocables.py)
+GN_RUN_BINARY_SCRIPT = $$shell_path($$QTWEBENGINE_ROOT/tools/scripts/gn_run_binary.py)
+GN_IMPORTS = $$PWD/qtpdf.gni
+GN_CREATE_PRI = true
+QMAKE_INTERNAL_INCLUDED_FILES = $$GN_IMPORTS $$GN_INCLUDES $$GN_FILE
+
+
diff --git a/src/pdf/qpdfbookmarkmodel.cpp b/src/pdf/qpdfbookmarkmodel.cpp
new file mode 100644
index 000000000..c9c365568
--- /dev/null
+++ b/src/pdf/qpdfbookmarkmodel.cpp
@@ -0,0 +1,363 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfbookmarkmodel.h"
+
+#include "qpdfdocument.h"
+#include "qpdfdocument_p.h"
+
+#include "third_party/pdfium/public/fpdf_doc.h"
+#include "third_party/pdfium/public/fpdfview.h"
+
+#include <QPointer>
+#include <QScopedPointer>
+#include <private/qabstractitemmodel_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class BookmarkNode
+{
+public:
+ explicit BookmarkNode(BookmarkNode *parentNode = nullptr)
+ : m_parentNode(parentNode)
+ , m_level(0)
+ , m_pageNumber(0)
+ {
+ }
+
+ ~BookmarkNode()
+ {
+ clear();
+ }
+
+ void clear()
+ {
+ qDeleteAll(m_childNodes);
+ m_childNodes.clear();
+ }
+
+ void appendChild(BookmarkNode *child)
+ {
+ m_childNodes.append(child);
+ }
+
+ BookmarkNode *child(int row) const
+ {
+ return m_childNodes.at(row);
+ }
+
+ int childCount() const
+ {
+ return m_childNodes.count();
+ }
+
+ int row() const
+ {
+ if (m_parentNode)
+ return m_parentNode->m_childNodes.indexOf(const_cast<BookmarkNode*>(this));
+
+ return 0;
+ }
+
+ BookmarkNode *parentNode() const
+ {
+ return m_parentNode;
+ }
+
+ QString title() const
+ {
+ return m_title;
+ }
+
+ void setTitle(const QString &title)
+ {
+ m_title = title;
+ }
+
+ int level() const
+ {
+ return m_level;
+ }
+
+ void setLevel(int level)
+ {
+ m_level = level;
+ }
+
+ int pageNumber() const
+ {
+ return m_pageNumber;
+ }
+
+ void setPageNumber(int pageNumber)
+ {
+ m_pageNumber = pageNumber;
+ }
+
+private:
+ QVector<BookmarkNode*> m_childNodes;
+ BookmarkNode *m_parentNode;
+
+ QString m_title;
+ int m_level;
+ int m_pageNumber;
+};
+
+
+class QPdfBookmarkModelPrivate : public QAbstractItemModelPrivate
+{
+public:
+ QPdfBookmarkModelPrivate()
+ : QAbstractItemModelPrivate()
+ , m_rootNode(new BookmarkNode(nullptr))
+ , m_document(nullptr)
+ , m_structureMode(QPdfBookmarkModel::TreeMode)
+ {
+ }
+
+ void rebuild()
+ {
+ Q_Q(QPdfBookmarkModel);
+
+ const bool documentAvailable = (m_document && m_document->status() == QPdfDocument::Ready);
+
+ if (documentAvailable) {
+ q->beginResetModel();
+ m_rootNode->clear();
+ QPdfMutexLocker lock;
+ appendChildNode(m_rootNode.data(), nullptr, 0, m_document->d->doc);
+ lock.unlock();
+ q->endResetModel();
+ } else {
+ if (m_rootNode->childCount() == 0) {
+ return;
+ } else {
+ q->beginResetModel();
+ m_rootNode->clear();
+ q->endResetModel();
+ }
+ }
+ }
+
+ void appendChildNode(BookmarkNode *parentBookmarkNode, FPDF_BOOKMARK parentBookmark, int level, FPDF_DOCUMENT document)
+ {
+ FPDF_BOOKMARK bookmark = FPDFBookmark_GetFirstChild(document, parentBookmark);
+
+ while (bookmark) {
+ BookmarkNode *childBookmarkNode = nullptr;
+
+ if (m_structureMode == QPdfBookmarkModel::TreeMode) {
+ childBookmarkNode = new BookmarkNode(parentBookmarkNode);
+ parentBookmarkNode->appendChild(childBookmarkNode);
+ } else if (m_structureMode == QPdfBookmarkModel::ListMode) {
+ childBookmarkNode = new BookmarkNode(m_rootNode.data());
+ m_rootNode->appendChild(childBookmarkNode);
+ }
+
+ const int titleLength = int(FPDFBookmark_GetTitle(bookmark, nullptr, 0));
+
+ QVector<ushort> titleBuffer(titleLength);
+ FPDFBookmark_GetTitle(bookmark, titleBuffer.data(), quint32(titleBuffer.length()));
+
+ const FPDF_DEST dest = FPDFBookmark_GetDest(document, bookmark);
+ const int pageNumber = FPDFDest_GetDestPageIndex(document, dest);
+
+ childBookmarkNode->setTitle(QString::fromUtf16(titleBuffer.data()));
+ childBookmarkNode->setLevel(level);
+ childBookmarkNode->setPageNumber(pageNumber);
+
+ // recurse down
+ appendChildNode(childBookmarkNode, bookmark, level + 1, document);
+
+ bookmark = FPDFBookmark_GetNextSibling(document, bookmark);
+ }
+ }
+
+ void _q_documentStatusChanged()
+ {
+ rebuild();
+ }
+
+ Q_DECLARE_PUBLIC(QPdfBookmarkModel)
+
+ QScopedPointer<BookmarkNode> m_rootNode;
+ QPointer<QPdfDocument> m_document;
+ QPdfBookmarkModel::StructureMode m_structureMode;
+};
+
+
+QPdfBookmarkModel::QPdfBookmarkModel(QObject *parent)
+ : QAbstractItemModel(*new QPdfBookmarkModelPrivate, parent)
+{
+}
+
+QPdfDocument* QPdfBookmarkModel::document() const
+{
+ Q_D(const QPdfBookmarkModel);
+
+ return d->m_document;
+}
+
+void QPdfBookmarkModel::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfBookmarkModel);
+
+ if (d->m_document == document)
+ return;
+
+ if (d->m_document)
+ disconnect(d->m_document, SIGNAL(statusChanged(QPdfDocument::Status)), this, SLOT(_q_documentStatusChanged()));
+
+ d->m_document = document;
+ emit documentChanged(d->m_document);
+
+ if (d->m_document)
+ connect(d->m_document, SIGNAL(statusChanged(QPdfDocument::Status)), this, SLOT(_q_documentStatusChanged()));
+
+ d->rebuild();
+}
+
+QPdfBookmarkModel::StructureMode QPdfBookmarkModel::structureMode() const
+{
+ Q_D(const QPdfBookmarkModel);
+
+ return d->m_structureMode;
+}
+
+void QPdfBookmarkModel::setStructureMode(StructureMode mode)
+{
+ Q_D(QPdfBookmarkModel);
+
+ if (d->m_structureMode == mode)
+ return;
+
+ d->m_structureMode = mode;
+ emit structureModeChanged(d->m_structureMode);
+
+ d->rebuild();
+}
+
+int QPdfBookmarkModel::columnCount(const QModelIndex &parent) const
+{
+ return 1;
+}
+
+QHash<int, QByteArray> QPdfBookmarkModel::roleNames() const
+{
+ QHash<int, QByteArray> names;
+
+ names[TitleRole] = "title";
+ names[LevelRole] = "level";
+ names[PageNumberRole] = "pageNumber";
+
+ return names;
+}
+
+QVariant QPdfBookmarkModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ const BookmarkNode *node = static_cast<BookmarkNode*>(index.internalPointer());
+ switch (role) {
+ case TitleRole:
+ return node->title();
+ case LevelRole:
+ return node->level();
+ case PageNumberRole:
+ return node->pageNumber();
+ default:
+ return QVariant();
+ }
+}
+
+QModelIndex QPdfBookmarkModel::index(int row, int column, const QModelIndex &parent) const
+{
+ Q_D(const QPdfBookmarkModel);
+
+ if (!hasIndex(row, column, parent))
+ return QModelIndex();
+
+ BookmarkNode *parentNode;
+
+ if (!parent.isValid())
+ parentNode = d->m_rootNode.data();
+ else
+ parentNode = static_cast<BookmarkNode*>(parent.internalPointer());
+
+ BookmarkNode *childNode = parentNode->child(row);
+ if (childNode)
+ return createIndex(row, column, childNode);
+ else
+ return QModelIndex();
+}
+
+QModelIndex QPdfBookmarkModel::parent(const QModelIndex &index) const
+{
+ Q_D(const QPdfBookmarkModel);
+
+ if (!index.isValid())
+ return QModelIndex();
+
+ const BookmarkNode *childNode = static_cast<BookmarkNode*>(index.internalPointer());
+ BookmarkNode *parentNode = childNode->parentNode();
+
+ if (parentNode == d->m_rootNode.data())
+ return QModelIndex();
+
+ return createIndex(parentNode->row(), 0, parentNode);
+}
+
+int QPdfBookmarkModel::rowCount(const QModelIndex &parent) const
+{
+ Q_D(const QPdfBookmarkModel);
+
+ if (parent.column() > 0)
+ return 0;
+
+ BookmarkNode *parentNode = nullptr;
+
+ if (!parent.isValid())
+ parentNode = d->m_rootNode.data();
+ else
+ parentNode = static_cast<BookmarkNode*>(parent.internalPointer());
+
+ return parentNode->childCount();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfbookmarkmodel.cpp"
diff --git a/src/pdf/qpdfdestination.cpp b/src/pdf/qpdfdestination.cpp
new file mode 100644
index 000000000..b70e031ca
--- /dev/null
+++ b/src/pdf/qpdfdestination.cpp
@@ -0,0 +1,145 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfdestination.h"
+#include "qpdfdestination_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPdfDestination
+ \since 5.15
+ \inmodule QtPdf
+
+ \brief The QPdfDestination class defines a location on a page in a PDF
+ document, and a suggested zoom level at which it is intended to be viewed.
+*/
+
+/*!
+ Constructs an invalid Destination.
+
+ \sa valid
+*/
+QPdfDestination::QPdfDestination()
+ : d(new QPdfDestinationPrivate())
+{
+}
+
+QPdfDestination::QPdfDestination(int page, QPointF location, qreal zoom)
+ : d(new QPdfDestinationPrivate(page, location, zoom))
+{
+}
+
+QPdfDestination::QPdfDestination(QPdfDestinationPrivate *d)
+ : d(d)
+{
+}
+
+QPdfDestination::QPdfDestination(const QPdfDestination &other)
+ : d(other.d)
+{
+}
+
+QPdfDestination::QPdfDestination(QPdfDestination &&other) noexcept
+ : d(std::move(other.d))
+{
+}
+
+QPdfDestination::~QPdfDestination()
+{
+}
+
+QPdfDestination &QPdfDestination::operator=(const QPdfDestination &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \property QPdfDestination::valid
+
+ This property holds whether the destination is valid.
+*/
+bool QPdfDestination::isValid() const
+{
+ return d->page >= 0;
+}
+
+/*!
+ \property QPdfDestination::page
+
+ This property holds the page number.
+*/
+int QPdfDestination::page() const
+{
+ return d->page;
+}
+
+/*!
+ \property QPdfDestination::location
+
+ This property holds the location on the page, in units of points.
+*/
+QPointF QPdfDestination::location() const
+{
+ return d->location;
+}
+
+/*!
+ \property QPdfDestination::zoom
+
+ This property holds the suggested magnification level, where 1.0 means default scale
+ (1 pixel = 1 point).
+*/
+qreal QPdfDestination::zoom() const
+{
+ return d->zoom;
+}
+
+QDebug operator<<(QDebug dbg, const QPdfDestination& dest)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QPdfDestination(page=" << dest.page()
+ << " location=" << dest.location()
+ << " zoom=" << dest.zoom();
+ dbg << ')';
+ return dbg;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfdestination.cpp"
diff --git a/src/pdf/qpdfdocument.cpp b/src/pdf/qpdfdocument.cpp
new file mode 100644
index 000000000..89b27da8b
--- /dev/null
+++ b/src/pdf/qpdfdocument.cpp
@@ -0,0 +1,803 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfdocument.h"
+#include "qpdfdocument_p.h"
+
+#include "third_party/pdfium/public/fpdf_doc.h"
+#include "third_party/pdfium/public/fpdf_text.h"
+
+#include <QDateTime>
+#include <QDebug>
+#include <QElapsedTimer>
+#include <QFile>
+#include <QHash>
+#include <QLoggingCategory>
+#include <QMutex>
+#include <QVector2D>
+
+QT_BEGIN_NAMESPACE
+
+// The library is not thread-safe at all, it has a lot of global variables.
+Q_GLOBAL_STATIC_WITH_ARGS(QMutex, pdfMutex, (QMutex::Recursive));
+static int libraryRefCount;
+static const double CharacterHitTolerance = 6.0;
+Q_LOGGING_CATEGORY(qLcDoc, "qt.pdf.document")
+
+QPdfMutexLocker::QPdfMutexLocker()
+ : QMutexLocker(pdfMutex())
+{
+}
+
+QPdfDocumentPrivate::QPdfDocumentPrivate()
+ : avail(nullptr)
+ , doc(nullptr)
+ , loadComplete(false)
+ , status(QPdfDocument::Null)
+ , lastError(QPdfDocument::NoError)
+ , pageCount(0)
+{
+ asyncBuffer.setData(QByteArray());
+ asyncBuffer.open(QIODevice::ReadWrite);
+
+ const QPdfMutexLocker lock;
+
+ if (libraryRefCount == 0)
+ FPDF_InitLibrary();
+ ++libraryRefCount;
+
+ // FPDF_FILEACCESS setup
+ m_Param = this;
+ m_GetBlock = fpdf_GetBlock;
+
+ // FX_FILEAVAIL setup
+ FX_FILEAVAIL::version = 1;
+ IsDataAvail = fpdf_IsDataAvail;
+
+ // FX_DOWNLOADHINTS setup
+ FX_DOWNLOADHINTS::version = 1;
+ AddSegment = fpdf_AddSegment;
+}
+
+QPdfDocumentPrivate::~QPdfDocumentPrivate()
+{
+ q->close();
+
+ const QPdfMutexLocker lock;
+
+ if (!--libraryRefCount)
+ FPDF_DestroyLibrary();
+}
+
+void QPdfDocumentPrivate::clear()
+{
+ QPdfMutexLocker lock;
+
+ if (doc)
+ FPDF_CloseDocument(doc);
+ doc = nullptr;
+
+ if (avail)
+ FPDFAvail_Destroy(avail);
+ avail = nullptr;
+ lock.unlock();
+
+ if (pageCount != 0) {
+ pageCount = 0;
+ emit q->pageCountChanged(pageCount);
+ }
+
+ loadComplete = false;
+
+ asyncBuffer.close();
+ asyncBuffer.setData(QByteArray());
+ asyncBuffer.open(QIODevice::ReadWrite);
+
+ if (sequentialSourceDevice)
+ sequentialSourceDevice->disconnect(q);
+}
+
+void QPdfDocumentPrivate::updateLastError()
+{
+ if (doc) {
+ lastError = QPdfDocument::NoError;
+ return;
+ }
+
+ QPdfMutexLocker lock;
+ const unsigned long error = FPDF_GetLastError();
+ lock.unlock();
+
+ switch (error) {
+ case FPDF_ERR_SUCCESS: lastError = QPdfDocument::NoError; break;
+ case FPDF_ERR_UNKNOWN: lastError = QPdfDocument::UnknownError; break;
+ case FPDF_ERR_FILE: lastError = QPdfDocument::FileNotFoundError; break;
+ case FPDF_ERR_FORMAT: lastError = QPdfDocument::InvalidFileFormatError; break;
+ case FPDF_ERR_PASSWORD: lastError = QPdfDocument::IncorrectPasswordError; break;
+ case FPDF_ERR_SECURITY: lastError = QPdfDocument::UnsupportedSecuritySchemeError; break;
+ default:
+ Q_UNREACHABLE();
+ }
+}
+
+void QPdfDocumentPrivate::load(QIODevice *newDevice, bool transferDeviceOwnership)
+{
+ if (transferDeviceOwnership)
+ ownDevice.reset(newDevice);
+ else
+ ownDevice.reset();
+
+ if (newDevice->isSequential()) {
+ sequentialSourceDevice = newDevice;
+ device = &asyncBuffer;
+ QNetworkReply *reply = qobject_cast<QNetworkReply*>(sequentialSourceDevice);
+
+ if (!reply) {
+ setStatus(QPdfDocument::Error);
+ qWarning() << "QPdfDocument: Loading from sequential devices only supported with QNetworkAccessManager.";
+ return;
+ }
+
+ if (reply->isFinished() && reply->error() != QNetworkReply::NoError) {
+ setStatus(QPdfDocument::Error);
+ return;
+ }
+
+ QObject::connect(reply, &QNetworkReply::finished, q, [this, reply](){
+ if (reply->error() != QNetworkReply::NoError || reply->bytesAvailable() == 0) {
+ this->setStatus(QPdfDocument::Error);
+ }
+ });
+
+ if (reply->header(QNetworkRequest::ContentLengthHeader).isValid())
+ _q_tryLoadingWithSizeFromContentHeader();
+ else
+ QObject::connect(reply, SIGNAL(metaDataChanged()), q, SLOT(_q_tryLoadingWithSizeFromContentHeader()));
+ } else {
+ device = newDevice;
+ initiateAsyncLoadWithTotalSizeKnown(device->size());
+ if (!avail) {
+ setStatus(QPdfDocument::Error);
+ return;
+ }
+
+ if (!doc)
+ tryLoadDocument();
+
+ if (!doc) {
+ updateLastError();
+ setStatus(QPdfDocument::Error);
+ return;
+ }
+
+ QPdfMutexLocker lock;
+ const int newPageCount = FPDF_GetPageCount(doc);
+ lock.unlock();
+ if (newPageCount != pageCount) {
+ pageCount = newPageCount;
+ emit q->pageCountChanged(pageCount);
+ }
+
+ // If it's a local file, and the first couple of pages are available,
+ // probably the whole document is available.
+ if (checkPageComplete(0) && (pageCount < 2 || checkPageComplete(1))) {
+ setStatus(QPdfDocument::Ready);
+ } else {
+ updateLastError();
+ setStatus(QPdfDocument::Error);
+ }
+ }
+}
+
+void QPdfDocumentPrivate::_q_tryLoadingWithSizeFromContentHeader()
+{
+ if (avail)
+ return;
+
+ const QNetworkReply *networkReply = qobject_cast<QNetworkReply*>(sequentialSourceDevice);
+ if (!networkReply) {
+ setStatus(QPdfDocument::Error);
+ return;
+ }
+
+ const QVariant contentLength = networkReply->header(QNetworkRequest::ContentLengthHeader);
+ if (!contentLength.isValid()) {
+ setStatus(QPdfDocument::Error);
+ return;
+ }
+
+ QObject::connect(sequentialSourceDevice, SIGNAL(readyRead()), q, SLOT(_q_copyFromSequentialSourceDevice()));
+
+ initiateAsyncLoadWithTotalSizeKnown(contentLength.toULongLong());
+
+ if (sequentialSourceDevice->bytesAvailable())
+ _q_copyFromSequentialSourceDevice();
+}
+
+void QPdfDocumentPrivate::initiateAsyncLoadWithTotalSizeKnown(quint64 totalSize)
+{
+ // FPDF_FILEACCESS setup
+ m_FileLen = totalSize;
+
+ const QPdfMutexLocker lock;
+
+ avail = FPDFAvail_Create(this, this);
+}
+
+void QPdfDocumentPrivate::_q_copyFromSequentialSourceDevice()
+{
+ if (loadComplete)
+ return;
+
+ const QByteArray data = sequentialSourceDevice->read(sequentialSourceDevice->bytesAvailable());
+ if (data.isEmpty())
+ return;
+
+ asyncBuffer.seek(asyncBuffer.size());
+ asyncBuffer.write(data);
+
+ checkComplete();
+}
+
+void QPdfDocumentPrivate::tryLoadDocument()
+{
+ QPdfMutexLocker lock;
+ switch (FPDFAvail_IsDocAvail(avail, this)) {
+ case PDF_DATA_ERROR:
+ qCDebug(qLcDoc) << "error loading";
+ break;
+ case PDF_DATA_NOTAVAIL:
+ qCDebug(qLcDoc) << "data not yet available";
+ lastError = QPdfDocument::DataNotYetAvailableError;
+ setStatus(QPdfDocument::Error);
+ break;
+ case PDF_DATA_AVAIL:
+ // all good
+ break;
+ }
+
+ Q_ASSERT(!doc);
+
+ doc = FPDFAvail_GetDocument(avail, password);
+ lock.unlock();
+
+ updateLastError();
+
+ if (lastError == QPdfDocument::IncorrectPasswordError) {
+ FPDF_CloseDocument(doc);
+ doc = nullptr;
+
+ setStatus(QPdfDocument::Error);
+ emit q->passwordRequired();
+ }
+}
+
+void QPdfDocumentPrivate::checkComplete()
+{
+ if (!avail || loadComplete)
+ return;
+
+ if (!doc)
+ tryLoadDocument();
+
+ if (!doc)
+ return;
+
+ loadComplete = true;
+
+ QPdfMutexLocker lock;
+
+ const int newPageCount = FPDF_GetPageCount(doc);
+ for (int i = 0; i < newPageCount; ++i) {
+ int result = PDF_DATA_NOTAVAIL;
+ while (result == PDF_DATA_NOTAVAIL) {
+ result = FPDFAvail_IsPageAvail(avail, i, this);
+ }
+
+ if (result == PDF_DATA_ERROR)
+ loadComplete = false;
+ }
+
+ lock.unlock();
+
+ if (loadComplete) {
+ if (newPageCount != pageCount) {
+ pageCount = newPageCount;
+ emit q->pageCountChanged(pageCount);
+ }
+
+ setStatus(QPdfDocument::Ready);
+ }
+}
+
+bool QPdfDocumentPrivate::checkPageComplete(int page)
+{
+ if (page < 0 || page >= pageCount)
+ return false;
+
+ if (loadComplete)
+ return true;
+
+ QPdfMutexLocker lock;
+ int result = PDF_DATA_NOTAVAIL;
+ while (result == PDF_DATA_NOTAVAIL)
+ result = FPDFAvail_IsPageAvail(avail, page, this);
+ lock.unlock();
+
+ if (result == PDF_DATA_ERROR)
+ updateLastError();
+
+ return (result != PDF_DATA_ERROR);
+}
+
+void QPdfDocumentPrivate::setStatus(QPdfDocument::Status documentStatus)
+{
+ if (status == documentStatus)
+ return;
+
+ status = documentStatus;
+ emit q->statusChanged(status);
+}
+
+FPDF_BOOL QPdfDocumentPrivate::fpdf_IsDataAvail(_FX_FILEAVAIL *pThis, size_t offset, size_t size)
+{
+ QPdfDocumentPrivate *d = static_cast<QPdfDocumentPrivate*>(pThis);
+ return offset + size <= static_cast<quint64>(d->device->size());
+}
+
+int QPdfDocumentPrivate::fpdf_GetBlock(void *param, unsigned long position, unsigned char *pBuf, unsigned long size)
+{
+ QPdfDocumentPrivate *d = static_cast<QPdfDocumentPrivate*>(reinterpret_cast<FPDF_FILEACCESS*>(param));
+ d->device->seek(position);
+ return qMax(qint64(0), d->device->read(reinterpret_cast<char *>(pBuf), size));
+
+}
+
+void QPdfDocumentPrivate::fpdf_AddSegment(_FX_DOWNLOADHINTS *pThis, size_t offset, size_t size)
+{
+ Q_UNUSED(pThis);
+ Q_UNUSED(offset);
+ Q_UNUSED(size);
+}
+
+QString QPdfDocumentPrivate::getText(FPDF_TEXTPAGE textPage, int startIndex, int count)
+{
+ QVector<ushort> buf(count + 1);
+ // TODO is that enough space in case one unicode character is more than one in utf-16?
+ int len = FPDFText_GetText(textPage, startIndex, count, buf.data());
+ Q_ASSERT(len - 1 <= count); // len is number of characters written, including the terminator
+ return QString::fromUtf16(buf.constData(), len - 1);
+}
+
+/*!
+ \class QPdfDocument
+ \since 5.10
+ \inmodule QtPdf
+
+ \brief The QPdfDocument class loads a PDF document and renders pages from it.
+*/
+
+/*!
+ Constructs a new document with parent object \a parent.
+*/
+QPdfDocument::QPdfDocument(QObject *parent)
+ : QObject(parent)
+ , d(new QPdfDocumentPrivate)
+{
+ d->q = this;
+}
+
+/*!
+ Destroys the document.
+*/
+QPdfDocument::~QPdfDocument()
+{
+}
+
+QPdfDocument::DocumentError QPdfDocument::load(const QString &fileName)
+{
+ qCDebug(qLcDoc) << "loading" << fileName;
+
+ close();
+
+ d->setStatus(QPdfDocument::Loading);
+
+ QScopedPointer<QFile> f(new QFile(fileName));
+ if (!f->open(QIODevice::ReadOnly)) {
+ d->lastError = FileNotFoundError;
+ d->setStatus(QPdfDocument::Error);
+ } else {
+ d->load(f.take(), /*transfer ownership*/true);
+ }
+ return d->lastError;
+}
+
+/*!
+ \enum QPdfDocument::Status
+
+ This enum describes the current status of the document.
+
+ \value Null The initial status after the document has been created or after it has been closed.
+ \value Loading The status after load() has been called and before the document is fully loaded.
+ \value Ready The status when the document is fully loaded and its data can be accessed.
+ \value Unloading The status after close() has been called on an open document.
+ At this point the document is still valid and all its data can be accessed.
+ \value Error The status after Loading, if loading has failed.
+
+ \sa QPdfDocument::status()
+*/
+
+/*!
+ Returns the current status of the document.
+*/
+QPdfDocument::Status QPdfDocument::status() const
+{
+ return d->status;
+}
+
+void QPdfDocument::load(QIODevice *device)
+{
+ close();
+
+ d->setStatus(QPdfDocument::Loading);
+
+ d->load(device, /*transfer ownership*/false);
+}
+
+void QPdfDocument::setPassword(const QString &password)
+{
+ const QByteArray newPassword = password.toUtf8();
+
+ if (d->password == newPassword)
+ return;
+
+ d->password = newPassword;
+ emit passwordChanged();
+}
+
+QString QPdfDocument::password() const
+{
+ return QString::fromUtf8(d->password);
+}
+
+/*!
+ \enum QPdfDocument::MetaDataField
+
+ This enum describes the available fields of meta data.
+
+ \value Title The document's title as QString.
+ \value Author The name of the person who created the document as QString.
+ \value Subject The subject of the document as QString.
+ \value Keywords Keywords associated with the document as QString.
+ \value Creator If the document was converted to PDF from another format,
+ the name of the conforming product that created the original document
+ from which it was converted as QString.
+ \value Producer If the document was converted to PDF from another format,
+ the name of the conforming product that converted it to PDF as QString.
+ \value CreationDate The date and time the document was created as QDateTime.
+ \value ModificationDate The date and time the document was most recently modified as QDateTime.
+
+ \sa QPdfDocument::metaData()
+*/
+
+/*!
+ Returns the meta data of the document for the given \a field.
+*/
+QVariant QPdfDocument::metaData(MetaDataField field) const
+{
+ if (!d->doc)
+ return QString();
+
+ QByteArray fieldName;
+ switch (field) {
+ case Title:
+ fieldName = "Title";
+ break;
+ case Subject:
+ fieldName = "Subject";
+ break;
+ case Author:
+ fieldName = "Author";
+ break;
+ case Keywords:
+ fieldName = "Keywords";
+ break;
+ case Producer:
+ fieldName = "Producer";
+ break;
+ case Creator:
+ fieldName = "Creator";
+ break;
+ case CreationDate:
+ fieldName = "CreationDate";
+ break;
+ case ModificationDate:
+ fieldName = "ModDate";
+ break;
+ }
+
+ QPdfMutexLocker lock;
+ const unsigned long len = FPDF_GetMetaText(d->doc, fieldName.constData(), nullptr, 0);
+
+ QVector<ushort> buf(len);
+ FPDF_GetMetaText(d->doc, fieldName.constData(), buf.data(), buf.length());
+ lock.unlock();
+
+ QString text = QString::fromUtf16(buf.data());
+
+ switch (field) {
+ case Title: // fall through
+ case Subject:
+ case Author:
+ case Keywords:
+ case Producer:
+ case Creator:
+ return text;
+ case CreationDate: // fall through
+ case ModificationDate:
+ // convert a "D:YYYYMMDDHHmmSSOHH'mm'" into "YYYY-MM-DDTHH:mm:ss+HH:mm"
+ if (text.startsWith(QLatin1String("D:")))
+ text = text.mid(2);
+ text.insert(4, QLatin1Char('-'));
+ text.insert(7, QLatin1Char('-'));
+ text.insert(10, QLatin1Char('T'));
+ text.insert(13, QLatin1Char(':'));
+ text.insert(16, QLatin1Char(':'));
+ text.replace(QLatin1Char('\''), QLatin1Char(':'));
+ if (text.endsWith(QLatin1Char(':')))
+ text.chop(1);
+
+ return QDateTime::fromString(text, Qt::ISODate);
+ }
+
+ return QVariant();
+}
+
+QPdfDocument::DocumentError QPdfDocument::error() const
+{
+ return d->lastError;
+}
+
+/*!
+ Closes the document.
+*/
+void QPdfDocument::close()
+{
+ if (!d->doc)
+ return;
+
+ d->setStatus(Unloading);
+
+ d->clear();
+
+ if (!d->password.isEmpty()) {
+ d->password.clear();
+ emit passwordChanged();
+ }
+
+ d->setStatus(Null);
+}
+
+/*!
+ Returns the amount of pages for the loaded document or \c 0 if
+ no document is loaded.
+*/
+int QPdfDocument::pageCount() const
+{
+ return d->pageCount;
+}
+
+QSizeF QPdfDocument::pageSize(int page) const
+{
+ QSizeF result;
+ if (!d->doc || !d->checkPageComplete(page))
+ return result;
+
+ const QPdfMutexLocker lock;
+
+ FPDF_GetPageSizeByIndex(d->doc, page, &result.rwidth(), &result.rheight());
+ return result;
+}
+
+/*!
+ Renders the \a page into a QImage of size \a imageSize according to the
+ provided \a renderOptions.
+
+ Returns the rendered page or an empty image in case of an error.
+
+ Note: If the \a imageSize does not match the aspect ratio of the page in the
+ PDF document, the page is rendered scaled, so that it covers the
+ complete \a imageSize.
+*/
+QImage QPdfDocument::render(int page, QSize imageSize, QPdfDocumentRenderOptions renderOptions)
+{
+ if (!d->doc || !d->checkPageComplete(page))
+ return QImage();
+
+ const QPdfMutexLocker lock;
+
+ QElapsedTimer timer;
+ if (Q_UNLIKELY(qLcDoc().isDebugEnabled()))
+ timer.start();
+ FPDF_PAGE pdfPage = FPDF_LoadPage(d->doc, page);
+ if (!pdfPage)
+ return QImage();
+
+ QImage result(imageSize, QImage::Format_ARGB32);
+ 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 QPdf::Rotate0:
+ rotation = 0;
+ break;
+ case QPdf::Rotate90:
+ rotation = 1;
+ break;
+ case QPdf::Rotate180:
+ rotation = 2;
+ break;
+ case QPdf::Rotate270:
+ rotation = 3;
+ break;
+ }
+
+ const QPdf::RenderFlags renderFlags = renderOptions.renderFlags();
+ int flags = 0;
+ if (renderFlags & QPdf::RenderAnnotations)
+ flags |= FPDF_ANNOT;
+ if (renderFlags & QPdf::RenderOptimizedForLcd)
+ flags |= FPDF_LCD_TEXT;
+ if (renderFlags & QPdf::RenderGrayscale)
+ flags |= FPDF_GRAYSCALE;
+ if (renderFlags & QPdf::RenderForceHalftone)
+ flags |= FPDF_RENDER_FORCEHALFTONE;
+ if (renderFlags & QPdf::RenderTextAliased)
+ flags |= FPDF_RENDER_NO_SMOOTHTEXT;
+ if (renderFlags & QPdf::RenderImageAliased)
+ flags |= FPDF_RENDER_NO_SMOOTHIMAGE;
+ if (renderFlags & QPdf::RenderPathAliased)
+ flags |= FPDF_RENDER_NO_SMOOTHPATH;
+
+ if (renderOptions.scaledClipRect().isValid()) {
+ const QRect &clipRect = renderOptions.scaledClipRect();
+
+ // TODO take rotation into account, like cpdf_page.cpp lines 145-178
+ float x0 = clipRect.left();
+ float y0 = clipRect.top();
+ float x1 = clipRect.left();
+ float y1 = clipRect.bottom();
+ float x2 = clipRect.right();
+ float y2 = clipRect.top();
+ QSizeF origSize = pageSize(page);
+ QVector2D pageScale(1, 1);
+ if (!renderOptions.scaledSize().isNull()) {
+ pageScale = QVector2D(renderOptions.scaledSize().width() / float(origSize.width()),
+ renderOptions.scaledSize().height() / float(origSize.height()));
+ }
+ FS_MATRIX matrix {(x2 - x0) / result.width() * pageScale.x(),
+ (y2 - y0) / result.width() * pageScale.x(),
+ (x1 - x0) / result.height() * pageScale.y(),
+ (y1 - y0) / result.height() * pageScale.y(), -x0, -y0};
+
+ FS_RECTF clipRectF { 0, 0, float(imageSize.width()), float(imageSize.height()) };
+
+ FPDF_RenderPageBitmapWithMatrix(bitmap, pdfPage, &matrix, &clipRectF, flags);
+ qCDebug(qLcDoc) << "matrix" << matrix.a << matrix.b << matrix.c << matrix.d << matrix.e << matrix.f;
+ qCDebug(qLcDoc) << "page" << page << "region" << renderOptions.scaledClipRect()
+ << "size" << imageSize << "took" << timer.elapsed() << "ms";
+ } else {
+ FPDF_RenderPageBitmap(bitmap, pdfPage, 0, 0, result.width(), result.height(), rotation, flags);
+ qCDebug(qLcDoc) << "page" << page << "size" << imageSize << "took" << timer.elapsed() << "ms";
+ }
+
+ FPDFBitmap_Destroy(bitmap);
+
+ FPDF_ClosePage(pdfPage);
+ return result;
+}
+
+/*!
+ Returns information about the text on the given \a page that can be found
+ between the given \a start and \a end points, if any.
+*/
+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);
+ FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
+ int startIndex = FPDFText_GetCharIndexAtPos(textPage, start.x(), pageHeight - start.y(),
+ CharacterHitTolerance, CharacterHitTolerance);
+ int endIndex = FPDFText_GetCharIndexAtPos(textPage, end.x(), pageHeight - end.y(),
+ CharacterHitTolerance, CharacterHitTolerance);
+ if (startIndex >= 0 && endIndex != startIndex) {
+ if (startIndex > endIndex)
+ qSwap(startIndex, endIndex);
+ int count = endIndex - startIndex + 1;
+ QString text = d->getText(textPage, startIndex, count);
+ QVector<QPolygonF> bounds;
+ int rectCount = FPDFText_CountRects(textPage, startIndex, endIndex - startIndex);
+ for (int i = 0; i < rectCount; ++i) {
+ double l, r, b, t;
+ FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
+ QPolygonF poly;
+ poly << QPointF(l, pageHeight - t);
+ poly << QPointF(r, pageHeight - t);
+ poly << QPointF(r, pageHeight - b);
+ poly << QPointF(l, pageHeight - b);
+ poly << QPointF(l, pageHeight - t);
+ bounds << poly;
+ }
+ qCDebug(qLcDoc) << page << start << "->" << end << "found" << startIndex << "->" << endIndex << text;
+ return QPdfSelection(text, bounds);
+ }
+
+ qCDebug(qLcDoc) << page << start << "->" << end << "nothing found";
+ return QPdfSelection();
+}
+
+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)
+ return QPdfSelection();
+ QString text = d->getText(textPage, 0, count);
+ QVector<QPolygonF> bounds;
+ int rectCount = FPDFText_CountRects(textPage, 0, count);
+ for (int i = 0; i < rectCount; ++i) {
+ double l, r, b, t;
+ FPDFText_GetRect(textPage, i, &l, &t, &r, &b);
+ QPolygonF poly;
+ poly << QPointF(l, pageHeight - t);
+ poly << QPointF(r, pageHeight - t);
+ poly << QPointF(r, pageHeight - b);
+ poly << QPointF(l, pageHeight - b);
+ poly << QPointF(l, pageHeight - t);
+ bounds << poly;
+ }
+ qCDebug(qLcDoc) << "on page" << page << "got" << count << "chars" << rectCount << "rects";
+ return QPdfSelection(text, bounds);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfdocument.cpp"
diff --git a/src/pdf/qpdfdocumentrenderoptions.qdoc b/src/pdf/qpdfdocumentrenderoptions.qdoc
new file mode 100644
index 000000000..cc5083f9d
--- /dev/null
+++ b/src/pdf/qpdfdocumentrenderoptions.qdoc
@@ -0,0 +1,139 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfdocumentrenderoptions.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPdfDocumentRenderOptions
+ \since 5.10
+ \inmodule QtPdf
+
+ \brief The QPdfDocumentRenderOptions class holds the options to render a page from a PDF document.
+
+ \sa QPdfDocument
+*/
+
+/*!
+ \fn QPdfDocumentRenderOptions::QPdfDocumentRenderOptions()
+
+ Constructs a QPdfDocumentRenderOptions object.
+*/
+
+/*!
+ \fn QPdf::Rotation QPdfDocumentRenderOptions::rotation() const
+
+ Returns the rotation used for rendering a page from a PDF document.
+
+ \sa setRotation()
+*/
+
+/*!
+ \fn void QPdfDocumentRenderOptions::setRotation(QPdf::Rotation rotation)
+
+ Sets the \a rotation used for rendering a page from a PDF document.
+
+ \sa rotation()
+*/
+
+/*!
+ \fn QPdf::RenderFlags QPdfDocumentRenderOptions::renderFlags() const
+
+ Returns the special flags used for rendering a page from a PDF document.
+
+ \sa setRenderFlags()
+*/
+
+/*!
+ \fn void QPdfDocumentRenderOptions::setRenderFlags(QPdf::RenderFlags flags)
+
+ Sets the special \a flags used for rendering a page from a PDF document.
+
+ \sa renderFlags()
+*/
+
+/*!
+ \fn QRect QPdfDocumentRenderOptions::scaledClipRect() const
+
+ Returns the rectangular region to be clipped from the page after having
+ been scaled to \l scaledSize().
+
+ \sa setScaledClipRect()
+*/
+
+/*!
+ \fn void QPdfDocumentRenderOptions::setScaledClipRect(QRect rect)
+
+ Sets the region \a rect to be clipped from the page after having been
+ scaled to \l scaledSize().
+
+ \sa scaledClipRect()
+*/
+
+/*!
+ \fn QRect QPdfDocumentRenderOptions::scaledSize() const
+
+ Returns the \a size of the page to be rendered, in pixels.
+
+ \sa setScaledSize()
+*/
+
+/*!
+ \fn void QPdfDocumentRenderOptions::setScaledSize(QSize size)
+
+ Sets the \a size of the page to be rendered, in pixels.
+
+ \sa scaledSize()
+*/
+
+/*!
+ \fn bool operator!=(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs)
+ \relates QPdfDocumentRenderOptions
+
+ Returns \c true if the options \a lhs and \a rhs are different, otherwise
+ returns \c false.
+*/
+
+/*!
+ \fn bool operator==(QPdfDocumentRenderOptions lhs, QPdfDocumentRenderOptions rhs)
+ \relates QPdfDocumentRenderOptions
+
+ Returns \c true if the options \a lhs and \a rhs are equal,
+ otherwise returns \c false.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/pdf/qpdflinkmodel.cpp b/src/pdf/qpdflinkmodel.cpp
new file mode 100644
index 000000000..96e6ddd5c
--- /dev/null
+++ b/src/pdf/qpdflinkmodel.cpp
@@ -0,0 +1,251 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdflinkmodel_p.h"
+#include "qpdflinkmodel_p_p.h"
+#include "qpdfdocument_p.h"
+
+#include "third_party/pdfium/public/fpdf_doc.h"
+#include "third_party/pdfium/public/fpdf_text.h"
+
+#include <QLoggingCategory>
+#include <QMetaEnum>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcLink, "qt.pdf.links")
+
+QPdfLinkModel::QPdfLinkModel(QObject *parent)
+ : QAbstractListModel(*(new QPdfLinkModelPrivate()), parent)
+{
+ QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role"));
+ for (int r = Qt::UserRole; r < int(Role::_Count); ++r)
+ m_roleNames.insert(r, QByteArray(rolesMetaEnum.valueToKey(r)).toLower());
+}
+
+QPdfLinkModel::~QPdfLinkModel() {}
+
+QHash<int, QByteArray> QPdfLinkModel::roleNames() const
+{
+ return m_roleNames;
+}
+
+int QPdfLinkModel::rowCount(const QModelIndex &parent) const
+{
+ Q_D(const QPdfLinkModel);
+ Q_UNUSED(parent)
+ return d->links.count();
+}
+
+QVariant QPdfLinkModel::data(const QModelIndex &index, int role) const
+{
+ Q_D(const QPdfLinkModel);
+ const QPdfLinkModelPrivate::Link &link = d->links.at(index.row());
+ switch (Role(role)) {
+ case Role::Rect:
+ return link.rect;
+ case Role::Url:
+ return link.url;
+ case Role::Page:
+ return link.page;
+ case Role::Location:
+ return link.location;
+ case Role::Zoom:
+ return link.zoom;
+ case Role::_Count:
+ break;
+ }
+ if (role == Qt::DisplayRole)
+ return link.toString();
+ return QVariant();
+}
+
+QPdfDocument *QPdfLinkModel::document() const
+{
+ Q_D(const QPdfLinkModel);
+ return d->document;
+}
+
+void QPdfLinkModel::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfLinkModel);
+ if (d->document == document)
+ return;
+ disconnect(d->document, &QPdfDocument::statusChanged, this, &QPdfLinkModel::onStatusChanged);
+ connect(document, &QPdfDocument::statusChanged, this, &QPdfLinkModel::onStatusChanged);
+ d->document = document;
+ emit documentChanged();
+ if (page())
+ setPage(0);
+ else
+ d->update();
+}
+
+int QPdfLinkModel::page() const
+{
+ Q_D(const QPdfLinkModel);
+ return d->page;
+}
+
+void QPdfLinkModel::setPage(int page)
+{
+ Q_D(QPdfLinkModel);
+ if (d->page == page)
+ return;
+
+ d->page = page;
+ emit pageChanged(page);
+ d->update();
+}
+
+QPdfLinkModelPrivate::QPdfLinkModelPrivate() : QAbstractItemModelPrivate()
+{
+}
+
+void QPdfLinkModelPrivate::update()
+{
+ Q_Q(QPdfLinkModel);
+ if (!document || !document->d->doc)
+ return;
+ auto doc = document->d->doc;
+ const QPdfMutexLocker lock;
+ FPDF_PAGE pdfPage = FPDF_LoadPage(doc, page);
+ if (!pdfPage) {
+ qWarning() << "failed to load page" << page;
+ return;
+ }
+ double pageHeight = FPDF_GetPageHeight(pdfPage);
+ q->beginResetModel();
+ links.clear();
+
+ // Iterate the ordinary links
+ int linkStart = 0;
+ bool ok = true;
+ while (ok) {
+ FPDF_LINK linkAnnot;
+ ok = FPDFLink_Enumerate(pdfPage, &linkStart, &linkAnnot);
+ if (!ok)
+ break;
+ FS_RECTF rect;
+ ok = FPDFLink_GetAnnotRect(linkAnnot, &rect);
+ if (!ok)
+ break;
+ Link linkData;
+ linkData.rect = QRectF(rect.left, pageHeight - rect.top,
+ rect.right - rect.left, rect.top - rect.bottom);
+ FPDF_DEST dest = FPDFLink_GetDest(doc, linkAnnot);
+ FPDF_ACTION action = FPDFLink_GetAction(linkAnnot);
+ if (FPDFAction_GetType(action) != PDFACTION_GOTO) {
+ qWarning() << "link action type" << FPDFAction_GetType(action) << "is not yet supported";
+ continue;
+ }
+ linkData.page = FPDFDest_GetDestPageIndex(doc, dest);
+ FPDF_BOOL hasX, hasY, hasZoom;
+ FS_FLOAT x, y, zoom;
+ ok = FPDFDest_GetLocationInPage(dest, &hasX, &hasY, &hasZoom, &x, &y, &zoom);
+ if (!ok)
+ break;
+ if (hasX && hasY)
+ linkData.location = QPointF(x, pageHeight - y);
+ if (hasZoom)
+ linkData.zoom = zoom;
+ links << linkData;
+ }
+
+ // Iterate the web links
+ FPDF_TEXTPAGE textPage = FPDFText_LoadPage(pdfPage);
+ if (textPage) {
+ FPDF_PAGELINK webLinks = FPDFLink_LoadWebLinks(textPage);
+ if (webLinks) {
+ int count = FPDFLink_CountWebLinks(webLinks);
+ for (int i = 0; i < count; ++i) {
+ Link linkData;
+ int len = FPDFLink_GetURL(webLinks, i, nullptr, 0);
+ if (len < 1) {
+ qWarning() << "URL" << i << "has length" << len;
+ } else {
+ QVector<unsigned short> buf(len);
+ int got = FPDFLink_GetURL(webLinks, i, buf.data(), len);
+ Q_ASSERT(got == len);
+ linkData.url = QString::fromUtf16(buf.data(), got - 1);
+ }
+ FPDFLink_GetTextRange(webLinks, i, &linkData.textStart, &linkData.textCharCount);
+ len = FPDFLink_CountRects(webLinks, i);
+ for (int r = 0; r < len; ++r) {
+ double left, top, right, bottom;
+ bool success = FPDFLink_GetRect(webLinks, i, r, &left, &top, &right, &bottom);
+ if (success) {
+ linkData.rect = QRectF(left, pageHeight - top, right - left, top - bottom);
+ links << linkData;
+ }
+ }
+ }
+ FPDFLink_CloseWebLinks(webLinks);
+ }
+ FPDFText_ClosePage(textPage);
+ }
+
+ // All done
+ FPDF_ClosePage(pdfPage);
+ if (Q_UNLIKELY(qLcLink().isDebugEnabled())) {
+ for (const Link &l : links)
+ qCDebug(qLcLink) << l.rect << l.toString();
+ }
+ q->endResetModel();
+}
+
+void QPdfLinkModel::onStatusChanged(QPdfDocument::Status status)
+{
+ Q_D(QPdfLinkModel);
+ qCDebug(qLcLink) << "sees document statusChanged" << status;
+ if (status == QPdfDocument::Ready)
+ d->update();
+}
+
+QString QPdfLinkModelPrivate::Link::toString() const
+{
+ QString ret;
+ if (page >= 0)
+ return QLatin1String("page ") + QString::number(page) +
+ QLatin1String(" location ") + QString::number(location.x()) + QLatin1Char(',') + QString::number(location.y()) +
+ QLatin1String(" zoom ") + QString::number(zoom);
+ else
+ return url.toString();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdflinkmodel_p.cpp"
diff --git a/src/pdf/qpdfnamespace.qdoc b/src/pdf/qpdfnamespace.qdoc
new file mode 100644
index 000000000..96bb090e9
--- /dev/null
+++ b/src/pdf/qpdfnamespace.qdoc
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \namespace QPdf
+ \inmodule QtPdf
+ \keyword QPdf Namespace
+
+ \brief The QPdf namespace contains miscellaneous identifiers
+ used throughout the QtPdf module.
+*/
+
+/*!
+ \enum QPdf::Rotation
+
+ This enum describes the rotation of the page for rendering.
+
+ \value Rotate0 Do not rotate (the default)
+ \value Rotate90 Rotate 90 degrees clockwise
+ \value Rotate180 Rotate 180 degrees
+ \value Rotate270 Rotate 270 degrees clockwise
+
+ \sa QPdfDocument::render()
+*/
+/*!
+ \enum QPdf::RenderFlag
+
+ This enum is used to describe how a page should be rendered.
+
+ \value NoRenderFlags The default value, representing no flags.
+ \value RenderAnnotations The page is rendered with annotations.
+ \value RenderOptimizedForLcd The text of the page is rendered optimized for LCD display.
+ \value RenderGrayscale The page is rendered grayscale.
+ \value RenderForceHalftone Always use halftones for rendering if the output image is stretched.
+ \value RenderTextAliased Anti-aliasing is disabled for rendering text.
+ \value RenderImageAliased Anti-aliasing is disabled for rendering images.
+ \value RenderPathAliased Anti-aliasing is disabled for rendering paths.
+
+ \sa QPdfDocument::render()
+*/
+
diff --git a/src/pdf/qpdfpagenavigation.cpp b/src/pdf/qpdfpagenavigation.cpp
new file mode 100644
index 000000000..497c1c2eb
--- /dev/null
+++ b/src/pdf/qpdfpagenavigation.cpp
@@ -0,0 +1,314 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfpagenavigation.h"
+
+#include "qpdfdocument.h"
+
+#include <private/qobject_p.h>
+
+#include <QPointer>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfPageNavigationPrivate : public QObjectPrivate
+{
+public:
+ QPdfPageNavigationPrivate()
+ : QObjectPrivate()
+ {
+ }
+
+ void update()
+ {
+ Q_Q(QPdfPageNavigation);
+
+ const bool documentAvailable = m_document && m_document->status() == QPdfDocument::Ready;
+
+ if (documentAvailable) {
+ const int newPageCount = m_document->pageCount();
+ if (m_pageCount != newPageCount) {
+ m_pageCount = newPageCount;
+ emit q->pageCountChanged(m_pageCount);
+ }
+ } else {
+ if (m_pageCount != 0) {
+ m_pageCount = 0;
+ emit q->pageCountChanged(m_pageCount);
+ }
+ }
+
+ if (m_currentPage != 0) {
+ m_currentPage = 0;
+ emit q->currentPageChanged(m_currentPage);
+ }
+
+ updatePrevNext();
+ }
+
+ void updatePrevNext()
+ {
+ Q_Q(QPdfPageNavigation);
+
+ const bool hasPreviousPage = m_currentPage > 0;
+ const bool hasNextPage = m_currentPage < (m_pageCount - 1);
+
+ if (m_canGoToPreviousPage != hasPreviousPage) {
+ m_canGoToPreviousPage = hasPreviousPage;
+ emit q->canGoToPreviousPageChanged(m_canGoToPreviousPage);
+ }
+
+ if (m_canGoToNextPage != hasNextPage) {
+ m_canGoToNextPage = hasNextPage;
+ emit q->canGoToNextPageChanged(m_canGoToNextPage);
+ }
+ }
+
+ void documentStatusChanged()
+ {
+ update();
+ }
+
+ Q_DECLARE_PUBLIC(QPdfPageNavigation)
+
+ QPointer<QPdfDocument> m_document = nullptr;
+ int m_currentPage = 0;
+ int m_pageCount = 0;
+ bool m_canGoToPreviousPage = false;
+ bool m_canGoToNextPage = false;
+
+ QMetaObject::Connection m_documentStatusChangedConnection;
+};
+
+/*!
+ \class QPdfPageNavigation
+ \since 5.10
+ \inmodule QtPdf
+
+ \brief The QPdfPageNavigation class handles the navigation through a PDF document.
+
+ \sa QPdfDocument
+*/
+
+
+/*!
+ Constructs a page navigation object with parent object \a parent.
+*/
+QPdfPageNavigation::QPdfPageNavigation(QObject *parent)
+ : QObject(*new QPdfPageNavigationPrivate, parent)
+{
+}
+
+/*!
+ Destroys the page navigation object.
+*/
+QPdfPageNavigation::~QPdfPageNavigation()
+{
+}
+
+/*!
+ \property QPdfPageNavigation::document
+ \brief The document instance on which this object navigates.
+
+ By default, this property is \c nullptr.
+
+ \sa document(), setDocument(), QPdfDocument
+*/
+
+/*!
+ Returns the document on which this object navigates, or a \c nullptr
+ if none has set before.
+
+ \sa QPdfDocument
+*/
+QPdfDocument* QPdfPageNavigation::document() const
+{
+ Q_D(const QPdfPageNavigation);
+
+ return d->m_document;
+}
+
+/*!
+ Sets the \a document this object navigates on.
+
+ After a new document has been set, the currentPage will be \c 0.
+
+ \sa QPdfDocument
+*/
+void QPdfPageNavigation::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfPageNavigation);
+
+ if (d->m_document == document)
+ return;
+
+ if (d->m_document)
+ disconnect(d->m_documentStatusChangedConnection);
+
+ d->m_document = document;
+ emit documentChanged(d->m_document);
+
+ if (d->m_document)
+ d->m_documentStatusChangedConnection = connect(d->m_document.data(), &QPdfDocument::statusChanged, this, [d](){ d->documentStatusChanged(); });
+
+ d->update();
+}
+
+/*!
+ \property QPdfPageNavigation::currentPage
+ \brief The current page number in the document.
+
+ \sa currentPage(), setCurrentPage()
+*/
+
+/*!
+ Returns the current page number or \c 0 if there is no document set.
+
+ After a document has been loaded, the currentPage will always be \c 0.
+*/
+int QPdfPageNavigation::currentPage() const
+{
+ Q_D(const QPdfPageNavigation);
+
+ return d->m_currentPage;
+}
+
+/*!
+ \fn void QPdfPageNavigation::setCurrentPage(int page)
+
+ Sets the current \a page number.
+*/
+void QPdfPageNavigation::setCurrentPage(int newPage)
+{
+ Q_D(QPdfPageNavigation);
+
+ if (newPage < 0 || newPage >= d->m_pageCount)
+ return;
+
+ if (d->m_currentPage == newPage)
+ return;
+
+ d->m_currentPage = newPage;
+ emit currentPageChanged(d->m_currentPage);
+
+ d->updatePrevNext();
+}
+
+/*!
+ \property QPdfPageNavigation::pageCount
+ \brief The number of pages in the document.
+
+ \sa pageCount()
+*/
+
+/*!
+ Returns the number of pages in the document or \c 0 if there
+ is no document set.
+*/
+int QPdfPageNavigation::pageCount() const
+{
+ Q_D(const QPdfPageNavigation);
+
+ return d->m_pageCount;
+}
+
+/*!
+ \property QPdfPageNavigation::canGoToPreviousPage
+ \brief Indicates whether there is a page before the current page.
+
+ \sa canGoToPreviousPage(), goToPreviousPage()
+*/
+
+/*!
+ Returns whether there is a page before the current one.
+*/
+bool QPdfPageNavigation::canGoToPreviousPage() const
+{
+ Q_D(const QPdfPageNavigation);
+
+ return d->m_canGoToPreviousPage;
+}
+
+/*!
+ \property QPdfPageNavigation::canGoToNextPage
+ \brief Indicates whether there is a page after the current page.
+
+ \sa canGoToNextPage(), goToNextPage()
+*/
+
+/*!
+ Returns whether there is a page after the current one.
+*/
+bool QPdfPageNavigation::canGoToNextPage() const
+{
+ Q_D(const QPdfPageNavigation);
+
+ return d->m_canGoToNextPage;
+}
+
+/*!
+ Changes the current page to the previous page.
+
+ If there is no previous page in the document, nothing happens.
+
+ \sa canGoToPreviousPage
+*/
+void QPdfPageNavigation::goToPreviousPage()
+{
+ Q_D(QPdfPageNavigation);
+
+ if (d->m_currentPage > 0)
+ setCurrentPage(d->m_currentPage - 1);
+}
+
+/*!
+ Changes the current page to the next page.
+
+ If there is no next page in the document, nothing happens.
+
+ \sa canGoToNextPage
+*/
+void QPdfPageNavigation::goToNextPage()
+{
+ Q_D(QPdfPageNavigation);
+
+ if (d->m_currentPage < d->m_pageCount - 1)
+ setCurrentPage(d->m_currentPage + 1);
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfpagenavigation.cpp"
diff --git a/src/pdf/qpdfpagerenderer.cpp b/src/pdf/qpdfpagerenderer.cpp
new file mode 100644
index 000000000..31d9f4e1e
--- /dev/null
+++ b/src/pdf/qpdfpagerenderer.cpp
@@ -0,0 +1,361 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfpagerenderer.h"
+
+#include <private/qobject_p.h>
+#include <QMutex>
+#include <QPdfDocument>
+#include <QPointer>
+#include <QThread>
+
+QT_BEGIN_NAMESPACE
+
+class RenderWorker : public QObject
+{
+ Q_OBJECT
+
+public:
+ RenderWorker();
+ ~RenderWorker();
+
+ void setDocument(QPdfDocument *document);
+
+public Q_SLOTS:
+ void requestPage(quint64 requestId, int page, QSize imageSize,
+ QPdfDocumentRenderOptions options);
+
+Q_SIGNALS:
+ void pageRendered(int page, QSize imageSize, const QImage &image,
+ QPdfDocumentRenderOptions options, quint64 requestId);
+
+private:
+ QPointer<QPdfDocument> m_document;
+ QMutex m_mutex;
+};
+
+class QPdfPageRendererPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QPdfPageRenderer)
+
+public:
+ QPdfPageRendererPrivate();
+ ~QPdfPageRendererPrivate();
+
+ void handleNextRequest();
+ void requestFinished(int page, QSize imageSize, const QImage &image,
+ QPdfDocumentRenderOptions options, quint64 requestId);
+
+ QPdfPageRenderer::RenderMode m_renderMode = QPdfPageRenderer::RenderMode::SingleThreaded;
+ QPointer<QPdfDocument> m_document;
+
+ struct PageRequest
+ {
+ quint64 id;
+ int pageNumber;
+ QSize imageSize;
+ QPdfDocumentRenderOptions options;
+ };
+
+ QVector<PageRequest> m_requests;
+ QVector<PageRequest> m_pendingRequests;
+ quint64 m_requestIdCounter = 1;
+
+ QThread *m_renderThread = nullptr;
+ QScopedPointer<RenderWorker> m_renderWorker;
+};
+
+Q_DECLARE_TYPEINFO(QPdfPageRendererPrivate::PageRequest, Q_PRIMITIVE_TYPE);
+
+
+RenderWorker::RenderWorker()
+ : m_document(nullptr)
+{
+}
+
+RenderWorker::~RenderWorker()
+{
+}
+
+void RenderWorker::setDocument(QPdfDocument *document)
+{
+ const QMutexLocker locker(&m_mutex);
+
+ if (m_document == document)
+ return;
+
+ m_document = document;
+}
+
+void RenderWorker::requestPage(quint64 requestId, int pageNumber, QSize imageSize,
+ QPdfDocumentRenderOptions options)
+{
+ const QMutexLocker locker(&m_mutex);
+
+ if (!m_document || m_document->status() != QPdfDocument::Ready)
+ return;
+
+ const QImage image = m_document->render(pageNumber, imageSize, options);
+
+ emit pageRendered(pageNumber, imageSize, image, options, requestId);
+}
+
+
+QPdfPageRendererPrivate::QPdfPageRendererPrivate()
+ : QObjectPrivate()
+ , m_renderWorker(new RenderWorker)
+{
+}
+
+QPdfPageRendererPrivate::~QPdfPageRendererPrivate()
+{
+ if (m_renderThread) {
+ m_renderThread->quit();
+ m_renderThread->wait();
+ }
+}
+
+void QPdfPageRendererPrivate::handleNextRequest()
+{
+ if (m_requests.isEmpty())
+ return;
+
+ const PageRequest request = m_requests.takeFirst();
+ m_pendingRequests.append(request);
+
+ QMetaObject::invokeMethod(m_renderWorker.data(), "requestPage", Qt::QueuedConnection,
+ Q_ARG(quint64, request.id), Q_ARG(int, request.pageNumber),
+ Q_ARG(QSize, request.imageSize), Q_ARG(QPdfDocumentRenderOptions,
+ request.options));
+}
+
+void QPdfPageRendererPrivate::requestFinished(int page, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions options, quint64 requestId)
+{
+ Q_UNUSED(image);
+ Q_UNUSED(requestId);
+ const auto it = std::find_if(m_pendingRequests.begin(), m_pendingRequests.end(),
+ [page, imageSize, options](const PageRequest &request){ return request.pageNumber == page && request.imageSize == imageSize && request.options == options; });
+
+ if (it != m_pendingRequests.end())
+ m_pendingRequests.erase(it);
+}
+
+/*!
+ \class QPdfPageRenderer
+ \since 5.11
+ \inmodule QtPdf
+
+ \brief The QPdfPageRenderer class encapsulates the rendering of pages of a PDF document.
+
+ The QPdfPageRenderer contains a queue that collects all render requests that are invoked through
+ requestPage(). Depending on the configured RenderMode the QPdfPageRenderer processes this queue
+ in the main UI thread on next event loop invocation (\c RenderMode::SingleThreaded) or in a separate worker thread
+ (\c RenderMode::MultiThreaded) and emits the result through the pageRendered() signal for each request once
+ the rendering is done.
+
+ \sa QPdfDocument
+*/
+
+
+/*!
+ Constructs a page renderer object with parent object \a parent.
+*/
+QPdfPageRenderer::QPdfPageRenderer(QObject *parent)
+ : QObject(*new QPdfPageRendererPrivate(), parent)
+{
+ Q_D(QPdfPageRenderer);
+
+ qRegisterMetaType<QPdfDocumentRenderOptions>();
+
+ connect(d->m_renderWorker.data(), &RenderWorker::pageRendered, this,
+ [this,d](int page, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions options, quint64 requestId) {
+ d->requestFinished(page, imageSize, image, options, requestId);
+ emit pageRendered(page, imageSize, image, options, requestId);
+ d->handleNextRequest();
+ });
+}
+
+/*!
+ Destroys the page renderer object.
+*/
+QPdfPageRenderer::~QPdfPageRenderer()
+{
+}
+
+/*!
+ \enum QPdfPageRenderer::RenderMode
+
+ This enum describes how the pages are rendered.
+
+ \value MultiThreaded All pages are rendered in a separate worker thread.
+ \value SingleThreaded All pages are rendered in the main UI thread (default).
+
+ \sa renderMode(), setRenderMode()
+*/
+
+/*!
+ \property QPdfPageRenderer::renderMode
+ \brief The mode the renderer uses to render the pages.
+
+ By default, this property is \c RenderMode::SingleThreaded.
+
+ \sa setRenderMode(), RenderMode
+*/
+
+/*!
+ Returns the mode of how the pages are rendered.
+
+ \sa RenderMode
+*/
+QPdfPageRenderer::RenderMode QPdfPageRenderer::renderMode() const
+{
+ Q_D(const QPdfPageRenderer);
+
+ return d->m_renderMode;
+}
+
+/*!
+ Sets the mode of how the pages are rendered to \a mode.
+
+ \sa RenderMode
+*/
+void QPdfPageRenderer::setRenderMode(RenderMode mode)
+{
+ Q_D(QPdfPageRenderer);
+
+ if (d->m_renderMode == mode)
+ return;
+
+ d->m_renderMode = mode;
+ emit renderModeChanged(d->m_renderMode);
+
+ if (d->m_renderMode == RenderMode::MultiThreaded) {
+ d->m_renderThread = new QThread;
+ d->m_renderWorker->moveToThread(d->m_renderThread);
+ d->m_renderThread->start();
+ } else {
+ d->m_renderThread->quit();
+ d->m_renderThread->wait();
+ delete d->m_renderThread;
+ d->m_renderThread = nullptr;
+
+ // pulling the object from another thread should be fine, once that thread is deleted
+ d->m_renderWorker->moveToThread(this->thread());
+ }
+}
+
+/*!
+ \property QPdfPageRenderer::document
+ \brief The document instance this object renders the pages from.
+
+ By default, this property is \c nullptr.
+
+ \sa document(), setDocument(), QPdfDocument
+*/
+
+/*!
+ Returns the document this objects renders the pages from, or a \c nullptr
+ if none has been set before.
+
+ \sa QPdfDocument
+*/
+QPdfDocument* QPdfPageRenderer::document() const
+{
+ Q_D(const QPdfPageRenderer);
+
+ return d->m_document;
+}
+
+/*!
+ Sets the \a document this object renders the pages from.
+
+ \sa QPdfDocument
+*/
+void QPdfPageRenderer::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfPageRenderer);
+
+ if (d->m_document == document)
+ return;
+
+ d->m_document = document;
+ emit documentChanged(d->m_document);
+
+ d->m_renderWorker->setDocument(d->m_document);
+}
+
+/*!
+ Requests the renderer to render the page \a pageNumber into a QImage of size \a imageSize
+ according to the provided \a options.
+
+ Once the rendering is done the pageRendered() signal is emitted with the result as parameters.
+
+ The return value is an ID that uniquely identifies the render request. If a request with the
+ same parameters is still in the queue, the ID of that queued request is returned.
+*/
+quint64 QPdfPageRenderer::requestPage(int pageNumber, QSize imageSize,
+ QPdfDocumentRenderOptions options)
+{
+ Q_D(QPdfPageRenderer);
+
+ if (!d->m_document || d->m_document->status() != QPdfDocument::Ready)
+ return 0;
+
+ for (const auto &request : qAsConst(d->m_pendingRequests)) {
+ if (request.pageNumber == pageNumber
+ && request.imageSize == imageSize
+ && request.options == options)
+ return request.id;
+ }
+
+ const auto id = d->m_requestIdCounter++;
+
+ QPdfPageRendererPrivate::PageRequest request;
+ request.id = id;
+ request.pageNumber = pageNumber;
+ request.imageSize = imageSize;
+ request.options = options;
+
+ d->m_requests.append(request);
+
+ d->handleNextRequest();
+
+ return id;
+}
+
+QT_END_NAMESPACE
+
+#include "qpdfpagerenderer.moc"
diff --git a/src/pdf/qpdfsearchmodel.cpp b/src/pdf/qpdfsearchmodel.cpp
new file mode 100644
index 000000000..27b7833fc
--- /dev/null
+++ b/src/pdf/qpdfsearchmodel.cpp
@@ -0,0 +1,324 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfdestination.h"
+#include "qpdfdocument_p.h"
+#include "qpdfsearchmodel.h"
+#include "qpdfsearchmodel_p.h"
+#include "qpdfsearchresult_p.h"
+
+#include "third_party/pdfium/public/fpdf_doc.h"
+#include "third_party/pdfium/public/fpdf_text.h"
+
+#include <QtCore/qelapsedtimer.h>
+#include <QtCore/qloggingcategory.h>
+#include <QtCore/QMetaEnum>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcS, "qt.pdf.search")
+
+static const int UpdateTimerInterval = 100;
+static const int ContextChars = 64;
+static const double CharacterHitTolerance = 6.0;
+
+QPdfSearchModel::QPdfSearchModel(QObject *parent)
+ : QAbstractListModel(*(new QPdfSearchModelPrivate()), parent)
+{
+ QMetaEnum rolesMetaEnum = metaObject()->enumerator(metaObject()->indexOfEnumerator("Role"));
+ for (int r = Qt::UserRole; r < int(Role::_Count); ++r) {
+ QByteArray roleName = QByteArray(rolesMetaEnum.valueToKey(r));
+ if (roleName.isEmpty())
+ continue;
+ roleName[0] = QChar::toLower(roleName[0]);
+ m_roleNames.insert(r, roleName);
+ }
+}
+
+QPdfSearchModel::~QPdfSearchModel() {}
+
+QHash<int, QByteArray> QPdfSearchModel::roleNames() const
+{
+ return m_roleNames;
+}
+
+int QPdfSearchModel::rowCount(const QModelIndex &parent) const
+{
+ Q_D(const QPdfSearchModel);
+ Q_UNUSED(parent)
+ return d->rowCountSoFar;
+}
+
+QVariant QPdfSearchModel::data(const QModelIndex &index, int role) const
+{
+ Q_D(const QPdfSearchModel);
+ const auto pi = const_cast<QPdfSearchModelPrivate*>(d)->pageAndIndexForResult(index.row());
+ if (pi.page < 0)
+ return QVariant();
+ switch (Role(role)) {
+ case Role::Page:
+ return pi.page;
+ case Role::IndexOnPage:
+ return pi.index;
+ case Role::Location:
+ return d->searchResults[pi.page][pi.index].location();
+ case Role::ContextBefore:
+ return d->searchResults[pi.page][pi.index].contextBefore();
+ case Role::ContextAfter:
+ return d->searchResults[pi.page][pi.index].contextAfter();
+ case Role::_Count:
+ break;
+ }
+ if (role == Qt::DisplayRole) {
+ const QString ret = d->searchResults[pi.page][pi.index].contextBefore() +
+ QLatin1String("<b>") + d->searchString + QLatin1String("</b>") +
+ d->searchResults[pi.page][pi.index].contextAfter();
+ return ret;
+ }
+ return QVariant();
+}
+
+void QPdfSearchModel::updatePage(int page)
+{
+ Q_D(QPdfSearchModel);
+ d->doSearch(page);
+}
+
+QString QPdfSearchModel::searchString() const
+{
+ Q_D(const QPdfSearchModel);
+ return d->searchString;
+}
+
+void QPdfSearchModel::setSearchString(QString searchString)
+{
+ Q_D(QPdfSearchModel);
+ if (d->searchString == searchString)
+ return;
+
+ d->searchString = searchString;
+ beginResetModel();
+ d->clearResults();
+ emit searchStringChanged();
+ endResetModel();
+}
+
+QVector<QPdfSearchResult> QPdfSearchModel::resultsOnPage(int page) const
+{
+ Q_D(const QPdfSearchModel);
+ const_cast<QPdfSearchModelPrivate *>(d)->doSearch(page);
+ if (d->searchResults.count() <= page)
+ return {};
+ return d->searchResults[page];
+}
+
+QPdfSearchResult QPdfSearchModel::resultAtIndex(int index) const
+{
+ Q_D(const QPdfSearchModel);
+ const auto pi = const_cast<QPdfSearchModelPrivate*>(d)->pageAndIndexForResult(index);
+ if (pi.page < 0)
+ return QPdfSearchResult();
+ return d->searchResults[pi.page][pi.index];
+}
+
+QPdfDocument *QPdfSearchModel::document() const
+{
+ Q_D(const QPdfSearchModel);
+ return d->document;
+}
+
+void QPdfSearchModel::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfSearchModel);
+ if (d->document == document)
+ return;
+
+ d->document = document;
+ d->clearResults();
+ emit documentChanged();
+}
+
+void QPdfSearchModel::timerEvent(QTimerEvent *event)
+{
+ Q_D(QPdfSearchModel);
+ if (event->timerId() != d->updateTimerId)
+ return;
+ if (!d->document || d->nextPageToUpdate >= d->document->pageCount()) {
+ if (d->document)
+ qCDebug(qLcS, "done updating search results on %d pages", d->searchResults.count());
+ killTimer(d->updateTimerId);
+ d->updateTimerId = -1;
+ }
+ d->doSearch(d->nextPageToUpdate++);
+}
+
+QPdfSearchModelPrivate::QPdfSearchModelPrivate() : QAbstractItemModelPrivate()
+{
+}
+
+void QPdfSearchModelPrivate::clearResults()
+{
+ Q_Q(QPdfSearchModel);
+ rowCountSoFar = 0;
+ searchResults.clear();
+ pagesSearched.clear();
+ if (document) {
+ searchResults.resize(document->pageCount());
+ pagesSearched.resize(document->pageCount());
+ } else {
+ searchResults.resize(0);
+ pagesSearched.resize(0);
+ }
+ nextPageToUpdate = 0;
+ updateTimerId = q->startTimer(UpdateTimerInterval);
+}
+
+bool QPdfSearchModelPrivate::doSearch(int page)
+{
+ if (page < 0 || page >= pagesSearched.count() || searchString.isEmpty())
+ return false;
+ if (pagesSearched[page])
+ return true;
+ Q_Q(QPdfSearchModel);
+
+ const QPdfMutexLocker lock;
+ QElapsedTimer timer;
+ timer.start();
+ FPDF_PAGE pdfPage = FPDF_LoadPage(document->d->doc, page);
+ if (!pdfPage) {
+ 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;
+ FPDF_ClosePage(pdfPage);
+ return false;
+ }
+ FPDF_SCHHANDLE sh = FPDFText_FindStart(textPage, searchString.utf16(), 0, 0);
+ QVector<QPdfSearchResult> newSearchResults;
+ while (FPDFText_FindNext(sh)) {
+ int idx = FPDFText_GetSchResultIndex(sh);
+ int count = FPDFText_GetSchCount(sh);
+ int rectCount = FPDFText_CountRects(textPage, idx, count);
+ QVector<QRectF> rects;
+ int startIndex = -1;
+ int endIndex = -1;
+ for (int r = 0; r < rectCount; ++r) {
+ double left, top, right, bottom;
+ FPDFText_GetRect(textPage, r, &left, &top, &right, &bottom);
+ rects << QRectF(left, pageHeight - top, right - left, top - bottom);
+ if (r == 0) {
+ startIndex = FPDFText_GetCharIndexAtPos(textPage, left, top,
+ CharacterHitTolerance, CharacterHitTolerance);
+ }
+ if (r == rectCount - 1) {
+ endIndex = FPDFText_GetCharIndexAtPos(textPage, right, top,
+ CharacterHitTolerance, CharacterHitTolerance);
+ }
+ qCDebug(qLcS) << rects.last() << "char idx" << startIndex << "->" << endIndex;
+ }
+ QString contextBefore, contextAfter;
+ if (startIndex >= 0 || endIndex >= 0) {
+ startIndex = qMax(0, startIndex - ContextChars);
+ endIndex += ContextChars;
+ int count = endIndex - startIndex + 1;
+ if (count > 0) {
+ QVector<ushort> buf(count + 1);
+ int len = FPDFText_GetText(textPage, startIndex, count, buf.data());
+ Q_ASSERT(len - 1 <= count); // len is number of characters written, including the terminator
+ QString context = QString::fromUtf16(buf.constData(), len - 1);
+ context = context.replace(QLatin1Char('\n'), QStringLiteral("\u23CE"));
+ context = context.remove(QLatin1Char('\r'));
+ // try to find the search string near the middle of the context if possible
+ int si = context.indexOf(searchString, ContextChars - 5, Qt::CaseInsensitive);
+ if (si < 0)
+ si = context.indexOf(searchString, Qt::CaseInsensitive);
+ if (si < 0)
+ qWarning() << "search string" << searchString << "not found in context" << context;
+ contextBefore = context.mid(0, si);
+ contextAfter = context.mid(si + searchString.length());
+ }
+ }
+ if (!rects.isEmpty())
+ newSearchResults << QPdfSearchResult(page, rects, contextBefore, contextAfter);
+ }
+ FPDFText_FindClose(sh);
+ FPDFText_ClosePage(textPage);
+ FPDF_ClosePage(pdfPage);
+ qCDebug(qLcS) << searchString << "took" << timer.elapsed() << "ms to find"
+ << newSearchResults.count() << "results on page" << page;
+
+ pagesSearched[page] = true;
+ searchResults[page] = newSearchResults;
+ if (newSearchResults.count() > 0) {
+ int rowsBefore = rowsBeforePage(page);
+ qCDebug(qLcS) << "from row" << rowsBefore << "rowCount" << rowCountSoFar << "increasing by" << newSearchResults.count();
+ rowCountSoFar += newSearchResults.count();
+ q->beginInsertRows(QModelIndex(), rowsBefore, rowsBefore + newSearchResults.count() - 1);
+ q->endInsertRows();
+ }
+ return true;
+}
+
+QPdfSearchModelPrivate::PageAndIndex QPdfSearchModelPrivate::pageAndIndexForResult(int resultIndex)
+{
+ const int pageCount = document->pageCount();
+ int totalSoFar = 0;
+ int previousTotalSoFar = 0;
+ for (int page = 0; page < pageCount; ++page) {
+ if (!pagesSearched[page])
+ doSearch(page);
+ totalSoFar += searchResults[page].count();
+ if (totalSoFar > resultIndex)
+ return {page, resultIndex - previousTotalSoFar};
+ previousTotalSoFar = totalSoFar;
+ }
+ return {-1, -1};
+}
+
+int QPdfSearchModelPrivate::rowsBeforePage(int page)
+{
+ int ret = 0;
+ for (int i = 0; i < page; ++i)
+ ret += searchResults[i].count();
+ return ret;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfsearchmodel.cpp"
diff --git a/src/pdf/qpdfsearchresult.cpp b/src/pdf/qpdfsearchresult.cpp
new file mode 100644
index 000000000..53da1c165
--- /dev/null
+++ b/src/pdf/qpdfsearchresult.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfsearchresult.h"
+#include "qpdfsearchresult_p.h"
+
+QT_BEGIN_NAMESPACE
+
+QPdfSearchResult::QPdfSearchResult() :
+ QPdfSearchResult(new QPdfSearchResultPrivate()) { }
+
+QPdfSearchResult::QPdfSearchResult(int page, QVector<QRectF> rects, QString contextBefore, QString contextAfter) :
+ QPdfSearchResult(new QPdfSearchResultPrivate(page, rects, contextBefore, contextAfter)) { }
+
+QPdfSearchResult::QPdfSearchResult(QPdfSearchResultPrivate *d) :
+ QPdfDestination(static_cast<QPdfDestinationPrivate *>(d)) { }
+
+QString QPdfSearchResult::contextBefore() const
+{
+ return static_cast<QPdfSearchResultPrivate *>(d.data())->contextBefore;
+}
+
+QString QPdfSearchResult::contextAfter() const
+{
+ return static_cast<QPdfSearchResultPrivate *>(d.data())->contextAfter;
+}
+
+QVector<QRectF> QPdfSearchResult::rectangles() const
+{
+ return static_cast<QPdfSearchResultPrivate *>(d.data())->rects;
+}
+
+QDebug operator<<(QDebug dbg, const QPdfSearchResult &searchResult)
+{
+ QDebugStateSaver saver(dbg);
+ dbg.nospace();
+ dbg << "QPdfSearchResult(page=" << searchResult.page()
+ << " contextBefore=" << searchResult.contextBefore()
+ << " contextAfter=" << searchResult.contextAfter()
+ << " rects=" << searchResult.rectangles();
+ dbg << ')';
+ return dbg;
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfsearchresult.cpp"
diff --git a/src/pdf/qpdfselection.cpp b/src/pdf/qpdfselection.cpp
new file mode 100644
index 000000000..e334f0fb6
--- /dev/null
+++ b/src/pdf/qpdfselection.cpp
@@ -0,0 +1,149 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfselection.h"
+#include "qpdfselection_p.h"
+#include <QGuiApplication>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QPdfSelection
+ \since 5.15
+ \inmodule QtPdf
+
+ \brief The QPdfSelection class defines a range of text that has been selected
+ on one page in a PDF document, and its geometric boundaries.
+
+ \sa QPdfDocument::getSelection()
+*/
+
+/*!
+ Constructs an invalid selection.
+
+ \sa valid
+*/
+QPdfSelection::QPdfSelection()
+ : d(new QPdfSelectionPrivate())
+{
+}
+
+/*!
+ \internal
+ Constructs a selection including the range of characters that make up the
+ \a text string, and which take up space on the page within the polygon
+ regions given in \a bounds.
+*/
+QPdfSelection::QPdfSelection(const QString &text, QVector<QPolygonF> bounds)
+ : d(new QPdfSelectionPrivate(text, bounds))
+{
+}
+
+QPdfSelection::QPdfSelection(QPdfSelectionPrivate *d)
+ : d(d)
+{
+}
+
+QPdfSelection::QPdfSelection(const QPdfSelection &other)
+ : d(other.d)
+{
+}
+
+QPdfSelection::QPdfSelection(QPdfSelection &&other) noexcept
+ : d(std::move(other.d))
+{
+}
+
+QPdfSelection::~QPdfSelection()
+{
+}
+
+QPdfSelection &QPdfSelection::operator=(const QPdfSelection &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ \property QPdfSelection::valid
+
+ This property holds whether the selection is valid.
+*/
+bool QPdfSelection::isValid() const
+{
+ return !d->bounds.isEmpty();
+}
+
+/*!
+ \property QPdfSelection::bounds
+
+ This property holds a set of regions that the selected text occupies on the
+ page, represented as polygons. The coordinate system for the polygons has
+ the origin at the upper-left corner of the page, and the units are
+ \l {https://en.wikipedia.org/wiki/Point_(typography)}{points}.
+
+ \note For now, the polygons returned from \l QPdfDocument::getSelection()
+ are always rectangles; but in the future it may be possible to represent
+ more complex regions.
+*/
+QVector<QPolygonF> QPdfSelection::bounds() const
+{
+ return d->bounds;
+}
+
+/*!
+ \property QPdfSelection::text
+
+ This property holds the selected text.
+*/
+QString QPdfSelection::text() const
+{
+ return d->text;
+}
+
+#if QT_CONFIG(clipboard)
+/*!
+ Copies \l text to the \l {QGuiApplication::clipboard()}{system clipboard}.
+*/
+void QPdfSelection::copyToClipboard(QClipboard::Mode mode) const
+{
+ QGuiApplication::clipboard()->setText(d->text, mode);
+}
+#endif
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfselection.cpp"
diff --git a/src/pdf/qtpdf.gni b/src/pdf/qtpdf.gni
new file mode 100644
index 000000000..c31f3e9a0
--- /dev/null
+++ b/src/pdf/qtpdf.gni
@@ -0,0 +1,7 @@
+include_dirs = [
+]
+
+deps = [
+ "//third_party/pdfium"
+]
+
diff --git a/src/pdf/quick/plugin.cpp b/src/pdf/quick/plugin.cpp
new file mode 100644
index 000000000..670fe0bf9
--- /dev/null
+++ b/src/pdf/quick/plugin.cpp
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtQml/qqml.h>
+#include <QtQml/qqmlcomponent.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlextensionplugin.h>
+#include "qquickpdfdocument_p.h"
+#include "qquickpdflinkmodel_p.h"
+#include "qquickpdfnavigationstack_p.h"
+#include "qquickpdfsearchmodel_p.h"
+#include "qquickpdfselection_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmlmodule QtQuick.Pdf 5.15
+ \title Qt Quick PDF QML Types
+ \ingroup qmlmodules
+ \brief Provides QML types for handling PDF documents.
+
+ This QML module contains types for handling PDF documents.
+
+ To use the types in this module, import the module with the following line:
+
+ \code
+ import QtQuick.Pdf 5.15
+ \endcode
+*/
+
+class QtQuick2PdfPlugin : public QQmlExtensionPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid)
+
+public:
+ QtQuick2PdfPlugin() : QQmlExtensionPlugin() { }
+
+ void initializeEngine(QQmlEngine *engine, const char *uri) override {
+ Q_UNUSED(uri);
+#ifdef QT_STATIC
+ Q_UNUSED(engine);
+#else
+ engine->addImportPath(QStringLiteral("qrc:/"));
+#endif
+ }
+
+ void registerTypes(const char *uri) override {
+ Q_ASSERT(QLatin1String(uri) == QLatin1String("QtQuick.Pdf"));
+
+ // Register the latest version, even if there are no new types or new revisions for existing types yet.
+ qmlRegisterModule(uri, 2, QT_VERSION_MINOR);
+
+ qmlRegisterType<QQuickPdfDocument>(uri, 5, 15, "PdfDocument");
+ qmlRegisterType<QQuickPdfLinkModel>(uri, 5, 15, "PdfLinkModel");
+ qmlRegisterType<QQuickPdfNavigationStack>(uri, 5, 15, "PdfNavigationStack");
+ qmlRegisterType<QQuickPdfSearchModel>(uri, 5, 15, "PdfSearchModel");
+ qmlRegisterType<QQuickPdfSelection>(uri, 5, 15, "PdfSelection");
+
+ qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfPageView.qml"), uri, 5, 15, "PdfPageView");
+ qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfMultiPageView.qml"), uri, 5, 15, "PdfMultiPageView");
+ qmlRegisterType(QUrl("qrc:/qt-project.org/qtpdf/qml/PdfScrollablePageView.qml"), uri, 5, 15, "PdfScrollablePageView");
+ }
+};
+
+QT_END_NAMESPACE
+
+#include "plugin.moc"
diff --git a/src/pdf/quick/plugins.qmltypes b/src/pdf/quick/plugins.qmltypes
new file mode 100644
index 000000000..a30361d33
--- /dev/null
+++ b/src/pdf/quick/plugins.qmltypes
@@ -0,0 +1,52 @@
+import QtQuick.tooling 1.2
+
+// This file describes the plugin-supplied types contained in the library.
+// It is used for QML tooling purposes only.
+//
+// This file was auto-generated by:
+// 'qmlplugindump -nonrelocatable QtQuick.Pdf 5.14'
+
+Module {
+ dependencies: [
+ "QtGraphicalEffects 1.12",
+ "QtQuick 2.14",
+ "QtQuick.Controls 2.14",
+ "QtQuick.Controls.Fusion 2.14",
+ "QtQuick.Controls.Fusion.impl 2.14",
+ "QtQuick.Controls.Imagine 2.14",
+ "QtQuick.Controls.Imagine.impl 2.14",
+ "QtQuick.Controls.Material 2.14",
+ "QtQuick.Controls.Material.impl 2.14",
+ "QtQuick.Controls.Universal 2.14",
+ "QtQuick.Controls.Universal.impl 2.12",
+ "QtQuick.Controls.impl 2.14",
+ "QtQuick.Shapes 1.14",
+ "QtQuick.Templates 2.14",
+ "QtQuick.Window 2.2"
+ ]
+ Component {
+ name: "QQuickPdfDocument"
+ prototype: "QObject"
+ exports: ["QtQuick.Pdf/PdfDocument 5.14"]
+ exportMetaObjectRevisions: [0]
+ Property { name: "source"; type: "QUrl" }
+ Property { name: "pageCount"; type: "int"; isReadonly: true }
+ Property { name: "password"; type: "string" }
+ Property { name: "status"; type: "QPdfDocument::Status"; isReadonly: true }
+ Property { name: "title"; type: "string"; isReadonly: true }
+ Property { name: "subject"; type: "string"; isReadonly: true }
+ Property { name: "author"; type: "string"; isReadonly: true }
+ Property { name: "keywords"; type: "string"; isReadonly: true }
+ Property { name: "producer"; type: "string"; isReadonly: true }
+ Property { name: "creator"; type: "string"; isReadonly: true }
+ Property { name: "creationDate"; type: "QDateTime"; isReadonly: true }
+ Property { name: "modificationDate"; type: "QDateTime"; isReadonly: true }
+ Signal { name: "passwordRequired" }
+ Signal { name: "metaDataLoaded" }
+ Method {
+ name: "pagePointSize"
+ type: "QSizeF"
+ Parameter { name: "page"; type: "int" }
+ }
+ }
+}
diff --git a/src/pdf/quick/qml/+material/PdfStyle.qml b/src/pdf/quick/qml/+material/PdfStyle.qml
new file mode 100644
index 000000000..12df30466
--- /dev/null
+++ b/src/pdf/quick/qml/+material/PdfStyle.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQml 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Material 2.14
+import QtQuick.Shapes 1.14
+
+QtObject {
+ property Control prototypeControl: Control { }
+ function withAlpha(color, alpha) {
+ return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha)
+ }
+ property color selectionColor: withAlpha(prototypeControl.palette.highlight, 0.5)
+ property color pageSearchResultsColor: withAlpha(Qt.lighter(Material.accentColor, 1.5), 0.5)
+ property color currentSearchResultStrokeColor: Material.accentColor
+ property real currentSearchResultStrokeWidth: 2
+ property color linkUnderscoreColor: prototypeControl.palette.link
+ property real linkUnderscoreStrokeWidth: 1
+ property var linkUnderscoreStrokeStyle: ShapePath.DashLine
+ property var linkUnderscoreDashPattern: [ 1, 4 ]
+}
diff --git a/src/pdf/quick/qml/+universal/PdfStyle.qml b/src/pdf/quick/qml/+universal/PdfStyle.qml
new file mode 100644
index 000000000..e92f2a080
--- /dev/null
+++ b/src/pdf/quick/qml/+universal/PdfStyle.qml
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQml 2.14
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Controls.Universal 2.14
+import QtQuick.Shapes 1.14
+
+QtObject {
+ property Control prototypeControl: Control { }
+ function withAlpha(color, alpha) {
+ return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha)
+ }
+ property color selectionColor: withAlpha(prototypeControl.palette.highlight, 0.5)
+ property color pageSearchResultsColor: withAlpha(Qt.lighter(Universal.accent, 1.5), 0.5)
+ property color currentSearchResultStrokeColor: Universal.accent
+ property real currentSearchResultStrokeWidth: 2
+ property color linkUnderscoreColor: prototypeControl.palette.link
+ property real linkUnderscoreStrokeWidth: 1
+ property var linkUnderscoreStrokeStyle: ShapePath.DashLine
+ property var linkUnderscoreDashPattern: [ 1, 4 ]
+}
diff --git a/src/pdf/quick/qml/PdfMultiPageView.qml b/src/pdf/quick/qml/PdfMultiPageView.qml
new file mode 100644
index 000000000..70bb5454f
--- /dev/null
+++ b/src/pdf/quick/qml/PdfMultiPageView.qml
@@ -0,0 +1,379 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Pdf 5.15
+import QtQuick.Shapes 1.14
+import QtQuick.Window 2.14
+
+Item {
+ // public API
+ // TODO 5.15: required property
+ property var document: undefined
+ property bool debug: false
+
+ property string selectedText
+ function selectAll() {
+ var currentItem = tableView.itemAtPos(0, tableView.contentY + root.height / 2)
+ if (currentItem !== null)
+ currentItem.selection.selectAll()
+ }
+ function copySelectionToClipboard() {
+ var currentItem = tableView.itemAtPos(0, tableView.contentY + root.height / 2)
+ if (debug)
+ console.log("currentItem", currentItem, "sel", currentItem.selection.text)
+ if (currentItem !== null)
+ currentItem.selection.copyToClipboard()
+ }
+
+ // page navigation
+ property alias currentPage: navigationStack.currentPage
+ property alias backEnabled: navigationStack.backAvailable
+ property alias forwardEnabled: navigationStack.forwardAvailable
+ function back() { navigationStack.back() }
+ function forward() { navigationStack.forward() }
+ function goToPage(page) {
+ if (page === navigationStack.currentPage)
+ return
+ goToLocation(page, Qt.point(0, 0), 0)
+ }
+ function goToLocation(page, location, zoom) {
+ if (zoom > 0)
+ root.renderScale = zoom
+ navigationStack.push(page, location, zoom)
+ searchModel.currentPage = page
+ }
+
+ // page scaling
+ property real renderScale: 1
+ property real pageRotation: 0
+ function resetScale() { root.renderScale = 1 }
+ function scaleToWidth(width, height) {
+ root.renderScale = width / (tableView.rot90 ? tableView.firstPagePointSize.height : tableView.firstPagePointSize.width)
+ }
+ function scaleToPage(width, height) {
+ var windowAspect = width / height
+ var pageAspect = tableView.firstPagePointSize.width / tableView.firstPagePointSize.height
+ if (tableView.rot90) {
+ if (windowAspect > pageAspect) {
+ root.renderScale = height / tableView.firstPagePointSize.width
+ } else {
+ root.renderScale = width / tableView.firstPagePointSize.height
+ }
+ } else {
+ if (windowAspect > pageAspect) {
+ root.renderScale = height / tableView.firstPagePointSize.height
+ } else {
+ root.renderScale = width / tableView.firstPagePointSize.width
+ }
+ }
+ }
+
+ // text search
+ property alias searchModel: searchModel
+ property alias searchString: searchModel.searchString
+ function searchBack() { --searchModel.currentResult }
+ function searchForward() { ++searchModel.currentResult }
+
+ id: root
+ PdfStyle { id: style }
+ TableView {
+ id: tableView
+ anchors.fill: parent
+ anchors.leftMargin: 2
+ model: root.document === undefined ? 0 : root.document.pageCount
+ rowSpacing: 6
+ property real rotationNorm: Math.round((360 + (root.pageRotation % 360)) % 360)
+ property bool rot90: rotationNorm == 90 || rotationNorm == 270
+ onRot90Changed: forceLayout()
+ property size firstPagePointSize: document === undefined ? Qt.size(0, 0) : document.pagePointSize(0)
+ contentWidth: document === undefined ? 0 : (rot90 ? document.maxPageHeight : document.maxPageWidth) * root.renderScale + vscroll.width + 2
+ // workaround for missing function (see https://codereview.qt-project.org/c/qt/qtdeclarative/+/248464)
+ function itemAtPos(x, y, includeSpacing) {
+ // we don't care about x (assume col 0), and assume includeSpacing is true
+ var ret = null
+ for (var i = 0; i < contentItem.children.length; ++i) {
+ var child = contentItem.children[i];
+ if (root.debug)
+ console.log(child, "@y", child.y)
+ if (child.y < y && (!ret || child.y > ret.y))
+ ret = child
+ }
+ if (root.debug && ret !== null)
+ console.log("given y", y, "found", ret, "@", ret.y)
+ return ret // the delegate with the largest y that is less than the given y
+ }
+ rowHeightProvider: function(row) { return (rot90 ? document.pagePointSize(row).width : document.pagePointSize(row).height) * root.renderScale }
+ delegate: Rectangle {
+ id: pageHolder
+ color: root.debug ? "beige" : "transparent"
+ Text {
+ visible: root.debug
+ anchors { right: parent.right; verticalCenter: parent.verticalCenter }
+ rotation: -90; text: pageHolder.width.toFixed(1) + "x" + pageHolder.height.toFixed(1) + "\n" +
+ image.width.toFixed(1) + "x" + image.height.toFixed(1)
+ }
+ implicitWidth: Math.max(root.width, (tableView.rot90 ? document.maxPageHeight : document.maxPageWidth) * root.renderScale)
+ implicitHeight: tableView.rot90 ? image.width : image.height
+ onImplicitWidthChanged: tableView.forceLayout()
+ objectName: "page " + index
+ property int delegateIndex: row // expose the context property for JS outside of the delegate
+ property alias selection: selection
+ Rectangle {
+ id: paper
+ width: image.width
+ height: image.height
+ rotation: root.pageRotation
+ anchors.centerIn: pinch.active ? undefined : parent
+ property size pagePointSize: document.pagePointSize(index)
+ property real pageScale: image.paintedWidth / pagePointSize.width
+ Image {
+ id: image
+ source: document.source
+ currentFrame: index
+ asynchronous: true
+ fillMode: Image.PreserveAspectFit
+ width: paper.pagePointSize.width * root.renderScale
+ height: paper.pagePointSize.height * root.renderScale
+ property real renderScale: root.renderScale
+ property real oldRenderScale: 1
+ onRenderScaleChanged: {
+ image.sourceSize.width = paper.pagePointSize.width * renderScale
+ image.sourceSize.height = 0
+ paper.scale = 1
+ searchHighlights.update()
+ }
+ }
+ Shape {
+ anchors.fill: parent
+ visible: image.status === Image.Ready
+ onVisibleChanged: searchHighlights.update()
+ ShapePath {
+ strokeWidth: -1
+ fillColor: style.pageSearchResultsColor
+ scale: Qt.size(paper.pageScale, paper.pageScale)
+ PathMultiline {
+ id: searchHighlights
+ function update() {
+ // paths could be a binding, but we need to be able to "kick" it sometimes
+ paths = searchModel.boundingPolygonsOnPage(index)
+ }
+ }
+ }
+ Connections {
+ target: searchModel
+ // whenever the highlights on the _current_ page change, they actually need to change on _all_ pages
+ // (usually because the search string has changed)
+ function onCurrentPageBoundingPolygonsChanged() { searchHighlights.update() }
+ }
+ ShapePath {
+ strokeWidth: -1
+ fillColor: style.selectionColor
+ scale: Qt.size(paper.pageScale, paper.pageScale)
+ PathMultiline {
+ paths: selection.geometry
+ }
+ }
+ }
+ Shape {
+ anchors.fill: parent
+ visible: image.status === Image.Ready && searchModel.currentPage === index
+ ShapePath {
+ strokeWidth: style.currentSearchResultStrokeWidth
+ strokeColor: style.currentSearchResultStrokeColor
+ fillColor: "transparent"
+ scale: Qt.size(paper.pageScale, paper.pageScale)
+ PathMultiline {
+ paths: searchModel.currentResultBoundingPolygons
+ }
+ }
+ }
+ PinchHandler {
+ id: pinch
+ minimumScale: 0.1
+ maximumScale: root.renderScale < 4 ? 2 : 1
+ minimumRotation: root.pageRotation
+ maximumRotation: root.pageRotation
+ enabled: image.sourceSize.width < 5000
+ onActiveChanged:
+ if (active) {
+ paper.z = 10
+ } else {
+ paper.z = 0
+ var centroidInPoints = Qt.point(pinch.centroid.position.x / root.renderScale,
+ pinch.centroid.position.y / root.renderScale)
+ var centroidInFlickable = tableView.mapFromItem(paper, pinch.centroid.position.x, pinch.centroid.position.y)
+ var newSourceWidth = image.sourceSize.width * paper.scale
+ var ratio = newSourceWidth / image.sourceSize.width
+ if (root.debug)
+ console.log("pinch ended on page", index, "with 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) {
+ var centroidOnPage = Qt.point(centroidInPoints.x * root.renderScale * ratio, centroidInPoints.y * root.renderScale * ratio)
+ paper.scale = 1
+ paper.x = 0
+ paper.y = 0
+ root.renderScale *= ratio
+ tableView.forceLayout()
+ if (tableView.rotationNorm == 0) {
+ tableView.contentX = pageHolder.x + tableView.originX + centroidOnPage.x - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + centroidOnPage.y - centroidInFlickable.y
+ } else if (tableView.rotationNorm == 90) {
+ tableView.contentX = pageHolder.x + tableView.originX + image.height - centroidOnPage.y - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + centroidOnPage.x - centroidInFlickable.y
+ } else if (tableView.rotationNorm == 180) {
+ tableView.contentX = pageHolder.x + tableView.originX + image.width - centroidOnPage.x - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + image.height - centroidOnPage.y - centroidInFlickable.y
+ } else if (tableView.rotationNorm == 270) {
+ tableView.contentX = pageHolder.x + tableView.originX + centroidOnPage.y - centroidInFlickable.x
+ tableView.contentY = pageHolder.y + tableView.originY + image.width - centroidOnPage.x - centroidInFlickable.y
+ }
+ if (root.debug)
+ console.log("contentX/Y adjusted to", tableView.contentX.toFixed(2), tableView.contentY.toFixed(2), "y @top", pageHolder.y)
+ tableView.returnToBounds()
+ }
+ }
+ grabPermissions: PointerHandler.CanTakeOverFromAnything
+ }
+ DragHandler {
+ id: textSelectionDrag
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ target: null
+ }
+ TapHandler {
+ id: tapHandler
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ }
+ Repeater {
+ model: PdfLinkModel {
+ id: linkModel
+ document: root.document
+ page: image.currentFrame
+ }
+ delegate: Shape {
+ x: rect.x * paper.pageScale
+ y: rect.y * paper.pageScale
+ width: rect.width * paper.pageScale
+ height: rect.height * paper.pageScale
+ ShapePath {
+ strokeWidth: style.linkUnderscoreStrokeWidth
+ strokeColor: style.linkUnderscoreColor
+ strokeStyle: style.linkUnderscoreStrokeStyle
+ dashPattern: style.linkUnderscoreDashPattern
+ startX: 0; startY: height
+ PathLine { x: width; y: height }
+ }
+ MouseArea { // TODO switch to TapHandler / HoverHandler in 5.15
+ id: linkMA
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ hoverEnabled: true
+ onClicked: {
+ if (page >= 0)
+ root.goToLocation(page, location, zoom)
+ else
+ Qt.openUrlExternally(url)
+ }
+ }
+ ToolTip {
+ visible: linkMA.containsMouse
+ delay: 1000
+ text: page >= 0 ?
+ ("page " + (page + 1) +
+ " location " + location.x.toFixed(1) + ", " + location.y.toFixed(1) +
+ " zoom " + zoom) : url
+ }
+ }
+ }
+ }
+ PdfSelection {
+ id: selection
+ document: root.document
+ page: image.currentFrame
+ fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / paper.pageScale,
+ textSelectionDrag.centroid.pressPosition.y / paper.pageScale)
+ toPoint: Qt.point(textSelectionDrag.centroid.position.x / paper.pageScale,
+ textSelectionDrag.centroid.position.y / paper.pageScale)
+ hold: !textSelectionDrag.active && !tapHandler.pressed
+ onTextChanged: root.selectedText = text
+ }
+ }
+ ScrollBar.vertical: ScrollBar {
+ id: vscroll
+ property bool moved: false
+ onPositionChanged: moved = true
+ onActiveChanged: {
+ var currentItem = tableView.itemAtPos(0, tableView.contentY + root.height / 2)
+ var currentPage = currentItem.delegateIndex
+ var currentLocation = Qt.point((tableView.contentX - currentItem.x + root.width / 2) / root.renderScale,
+ (tableView.contentY - currentItem.y + root.height / 2) / root.renderScale)
+ if (active) {
+ moved = false
+ navigationStack.push(currentPage, currentLocation, root.renderScale)
+ } else if (moved) {
+ navigationStack.update(currentPage, currentLocation, root.renderScale)
+ }
+ }
+ }
+ ScrollBar.horizontal: ScrollBar { }
+ }
+ onRenderScaleChanged: {
+ tableView.forceLayout()
+ var currentItem = tableView.itemAtPos(tableView.contentX + root.width / 2, tableView.contentY + root.height / 2)
+ if (currentItem !== undefined)
+ navigationStack.update(currentItem.delegateIndex, Qt.point(currentItem.x / renderScale, currentItem.y / renderScale), renderScale)
+ }
+ PdfNavigationStack {
+ id: navigationStack
+ onJumped: {
+ root.renderScale = zoom
+ tableView.contentX = Math.max(0, location.x - root.width / 2) * root.renderScale
+ tableView.contentY = tableView.originY + root.document.heightSumBeforePage(page, tableView.rowSpacing / root.renderScale) * root.renderScale
+ if (root.debug) {
+ console.log("going to page", page,
+ "@y", root.document.heightSumBeforePage(page, tableView.rowSpacing / root.renderScale) * root.renderScale,
+ "ended up @", tableView.contentY, "originY is", tableView.originY)
+ }
+ }
+ }
+ PdfSearchModel {
+ id: searchModel
+ document: root.document === undefined ? null : root.document
+ onCurrentPageChanged: if (currentPage != navigationStack.currentPage) root.goToPage(currentPage)
+ }
+}
diff --git a/src/pdf/quick/qml/PdfPageView.qml b/src/pdf/quick/qml/PdfPageView.qml
new file mode 100644
index 000000000..b90ad2d7f
--- /dev/null
+++ b/src/pdf/quick/qml/PdfPageView.qml
@@ -0,0 +1,276 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Pdf 5.15
+import QtQuick.Shapes 1.14
+import Qt.labs.animation 1.0
+
+Rectangle {
+ // public API
+ // TODO 5.15: required property
+ property var document: undefined
+ property alias status: image.status
+
+ property alias selectedText: selection.text
+ function selectAll() {
+ selection.selectAll()
+ }
+ function copySelectionToClipboard() {
+ selection.copyToClipboard()
+ }
+
+ // page navigation
+ property alias currentPage: navigationStack.currentPage
+ property alias backEnabled: navigationStack.backAvailable
+ property alias forwardEnabled: navigationStack.forwardAvailable
+ function back() { navigationStack.back() }
+ function forward() { navigationStack.forward() }
+ function goToPage(page) { goToLocation(page, Qt.point(0, 0), 0) }
+ function goToLocation(page, location, zoom) {
+ if (zoom > 0)
+ root.renderScale = zoom
+ navigationStack.push(page, location, zoom)
+ }
+
+ // page scaling
+ property real renderScale: 1
+ property alias sourceSize: image.sourceSize
+ function resetScale() {
+ image.sourceSize.width = 0
+ image.sourceSize.height = 0
+ root.x = 0
+ root.y = 0
+ root.scale = 1
+ }
+ function scaleToWidth(width, height) {
+ var halfRotation = Math.abs(root.rotation % 180)
+ image.sourceSize = Qt.size((halfRotation > 45 && halfRotation < 135) ? height : width, 0)
+ root.x = 0
+ root.y = 0
+ image.centerInSize = Qt.size(width, height)
+ image.centerOnLoad = true
+ image.vCenterOnLoad = (halfRotation > 45 && halfRotation < 135)
+ root.scale = 1
+ }
+ function scaleToPage(width, height) {
+ var windowAspect = width / height
+ var halfRotation = Math.abs(root.rotation % 180)
+ var pagePointSize = document.pagePointSize(navigationStack.currentPage)
+ if (halfRotation > 45 && halfRotation < 135) {
+ // rotated 90 or 270º
+ var pageAspect = pagePointSize.height / pagePointSize.width
+ if (windowAspect > pageAspect) {
+ image.sourceSize = Qt.size(height, 0)
+ } else {
+ image.sourceSize = Qt.size(0, width)
+ }
+ } else {
+ var pageAspect = pagePointSize.width / pagePointSize.height
+ if (windowAspect > pageAspect) {
+ image.sourceSize = Qt.size(0, height)
+ } else {
+ image.sourceSize = Qt.size(width, 0)
+ }
+ }
+ image.centerInSize = Qt.size(width, height)
+ image.centerOnLoad = true
+ image.vCenterOnLoad = true
+ root.scale = 1
+ }
+
+ // text search
+ property alias searchModel: searchModel
+ property alias searchString: searchModel.searchString
+ function searchBack() { --searchModel.currentResult }
+ function searchForward() { ++searchModel.currentResult }
+
+ // implementation
+ id: root
+ width: image.width
+ height: image.height
+
+ PdfSelection {
+ id: selection
+ document: root.document
+ page: navigationStack.currentPage
+ fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / image.pageScale, textSelectionDrag.centroid.pressPosition.y / image.pageScale)
+ toPoint: Qt.point(textSelectionDrag.centroid.position.x / image.pageScale, textSelectionDrag.centroid.position.y / image.pageScale)
+ hold: !textSelectionDrag.active && !tapHandler.pressed
+ }
+
+ PdfSearchModel {
+ id: searchModel
+ document: root.document === undefined ? null : root.document
+ onCurrentPageChanged: root.goToPage(currentPage)
+ }
+
+ PdfNavigationStack {
+ id: navigationStack
+ onCurrentPageChanged: searchModel.currentPage = currentPage
+ // TODO onCurrentLocationChanged: position currentLocation.x and .y in middle // currentPageChanged() MUST occur first!
+ onCurrentZoomChanged: root.renderScale = currentZoom
+ // TODO deal with horizontal location (need WheelHandler or Flickable probably)
+ }
+
+ Image {
+ id: image
+ currentFrame: navigationStack.currentPage
+ source: document.status === PdfDocument.Ready ? document.source : ""
+ asynchronous: true
+ fillMode: Image.PreserveAspectFit
+ property bool centerOnLoad: false
+ property bool vCenterOnLoad: false
+ property size centerInSize
+ property real pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width
+ function reRenderIfNecessary() {
+ var newSourceWidth = image.sourceSize.width * root.scale
+ var ratio = newSourceWidth / image.sourceSize.width
+ if (ratio > 1.1 || ratio < 0.9) {
+ image.sourceSize.width = newSourceWidth
+ image.sourceSize.height = 0
+ root.scale = 1
+ }
+ }
+ onStatusChanged:
+ if (status == Image.Ready && centerOnLoad) {
+ root.x = (centerInSize.width - image.implicitWidth) / 2
+ root.y = vCenterOnLoad ? (centerInSize.height - image.implicitHeight) / 2 : 0
+ centerOnLoad = false
+ vCenterOnLoad = false
+ }
+ }
+ onRenderScaleChanged: {
+ image.sourceSize.width = document.pagePointSize(navigationStack.currentPage).width * renderScale
+ image.sourceSize.height = 0
+ root.scale = 1
+ }
+
+ Shape {
+ anchors.fill: parent
+ opacity: 0.25
+ visible: image.status === Image.Ready
+ ShapePath {
+ strokeWidth: 1
+ strokeColor: "cyan"
+ fillColor: "steelblue"
+ scale: Qt.size(image.pageScale, image.pageScale)
+ PathMultiline {
+ paths: searchModel.currentPageBoundingPolygons
+ }
+ }
+ ShapePath {
+ strokeWidth: 1
+ strokeColor: "orange"
+ fillColor: "cyan"
+ scale: Qt.size(image.pageScale, image.pageScale)
+ PathMultiline {
+ paths: searchModel.currentResultBoundingPolygons
+ }
+ }
+ ShapePath {
+ fillColor: "orange"
+ scale: Qt.size(image.pageScale, image.pageScale)
+ PathMultiline {
+ paths: selection.geometry
+ }
+ }
+ }
+
+ Repeater {
+ model: PdfLinkModel {
+ id: linkModel
+ document: root.document
+ page: navigationStack.currentPage
+ }
+ delegate: Rectangle {
+ color: "transparent"
+ border.color: "lightgrey"
+ x: rect.x * image.pageScale
+ y: rect.y * image.pageScale
+ width: rect.width * image.pageScale
+ height: rect.height * image.pageScale
+ MouseArea { // TODO switch to TapHandler / HoverHandler in 5.15
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ if (page >= 0)
+ navigationStack.push(page, Qt.point(0, 0), root.renderScale)
+ else
+ Qt.openUrlExternally(url)
+ }
+ }
+ }
+ }
+
+ PinchHandler {
+ id: pinch
+ minimumScale: 0.1
+ maximumScale: 10
+ minimumRotation: 0
+ maximumRotation: 0
+ onActiveChanged: if (!active) image.reRenderIfNecessary()
+ grabPermissions: PinchHandler.TakeOverForbidden // don't allow takeover if pinch has started
+ }
+ DragHandler {
+ id: pageMovingTouchDrag
+ acceptedDevices: PointerDevice.TouchScreen
+ }
+ DragHandler {
+ id: pageMovingMiddleMouseDrag
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ acceptedButtons: Qt.MiddleButton
+ snapMode: DragHandler.NoSnap
+ }
+ DragHandler {
+ id: textSelectionDrag
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ target: null
+ }
+ TapHandler {
+ id: tapHandler
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ }
+ // prevent it from being scrolled out of view
+ BoundaryRule on x {
+ minimum: 100 - root.width
+ maximum: root.parent.width - 100
+ }
+ BoundaryRule on y {
+ minimum: 100 - root.height
+ maximum: root.parent.height - 100
+ }
+}
diff --git a/src/pdf/quick/qml/PdfScrollablePageView.qml b/src/pdf/quick/qml/PdfScrollablePageView.qml
new file mode 100644
index 000000000..6076e57df
--- /dev/null
+++ b/src/pdf/quick/qml/PdfScrollablePageView.qml
@@ -0,0 +1,290 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Pdf 5.15
+import QtQuick.Shapes 1.14
+import Qt.labs.animation 1.0
+
+Flickable {
+ // public API
+ // TODO 5.15: required property
+ property var document: undefined
+ property bool debug: false
+ property alias status: image.status
+
+ property alias selectedText: selection.text
+ function selectAll() {
+ selection.selectAll()
+ }
+ function copySelectionToClipboard() {
+ selection.copyToClipboard()
+ }
+
+ // page navigation
+ property alias currentPage: navigationStack.currentPage
+ property alias backEnabled: navigationStack.backAvailable
+ property alias forwardEnabled: navigationStack.forwardAvailable
+ function back() { navigationStack.back() }
+ function forward() { navigationStack.forward() }
+ function goToPage(page) {
+ if (page === navigationStack.currentPage)
+ return
+ goToLocation(page, Qt.point(0, 0), 0)
+ }
+ function goToLocation(page, location, zoom) {
+ if (zoom > 0)
+ root.renderScale = zoom
+ navigationStack.push(page, location, zoom)
+ }
+
+ // page scaling
+ property real renderScale: 1
+ property real pageRotation: 0
+ property alias sourceSize: image.sourceSize
+ function resetScale() {
+ paper.scale = 1
+ root.renderScale = 1
+ }
+ function scaleToWidth(width, height) {
+ var pagePointSize = document.pagePointSize(navigationStack.currentPage)
+ root.renderScale = root.width / (paper.rot90 ? pagePointSize.height : pagePointSize.width)
+ if (debug)
+ console.log("scaling", pagePointSize, "to fit", root.width, "rotated?", paper.rot90, "scale", root.renderScale)
+ root.contentX = 0
+ root.contentY = 0
+ }
+ function scaleToPage(width, height) {
+ var pagePointSize = document.pagePointSize(navigationStack.currentPage)
+ root.renderScale = Math.min(
+ root.width / (paper.rot90 ? pagePointSize.height : pagePointSize.width),
+ root.height / (paper.rot90 ? pagePointSize.width : pagePointSize.height) )
+ root.contentX = 0
+ root.contentY = 0
+ }
+
+ // text search
+ property alias searchModel: searchModel
+ property alias searchString: searchModel.searchString
+ function searchBack() { --searchModel.currentResult }
+ function searchForward() { ++searchModel.currentResult }
+
+ // implementation
+ id: root
+ PdfStyle { id: style }
+ contentWidth: paper.width
+ contentHeight: paper.height
+ ScrollBar.vertical: ScrollBar {
+ onActiveChanged:
+ if (!active ) {
+ var currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale,
+ (root.contentY + root.height / 2) / root.renderScale)
+ navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale)
+ }
+ }
+ ScrollBar.horizontal: ScrollBar {
+ onActiveChanged:
+ if (!active ) {
+ var currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale,
+ (root.contentY + root.height / 2) / root.renderScale)
+ navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale)
+ }
+ }
+
+ onRenderScaleChanged: {
+ image.sourceSize.width = document.pagePointSize(navigationStack.currentPage).width * renderScale
+ image.sourceSize.height = 0
+ paper.scale = 1
+ var currentLocation = Qt.point((root.contentX + root.width / 2) / root.renderScale,
+ (root.contentY + root.height / 2) / root.renderScale)
+ navigationStack.update(navigationStack.currentPage, currentLocation, root.renderScale)
+ }
+
+ PdfSelection {
+ id: selection
+ document: root.document
+ page: navigationStack.currentPage
+ fromPoint: Qt.point(textSelectionDrag.centroid.pressPosition.x / image.pageScale,
+ textSelectionDrag.centroid.pressPosition.y / image.pageScale)
+ toPoint: Qt.point(textSelectionDrag.centroid.position.x / image.pageScale,
+ textSelectionDrag.centroid.position.y / image.pageScale)
+ hold: !textSelectionDrag.active && !tapHandler.pressed
+ }
+
+ PdfSearchModel {
+ id: searchModel
+ document: root.document === undefined ? null : root.document
+ onCurrentPageChanged: root.goToPage(currentPage)
+ }
+
+ PdfNavigationStack {
+ id: navigationStack
+ onJumped: {
+ root.renderScale = zoom
+ root.contentX = Math.max(0, location.x * root.renderScale - root.width / 2)
+ root.contentY = Math.max(0, location.y * root.renderScale - root.height / 2)
+ if (root.debug)
+ console.log("going to zoom", zoom, "loc", location,
+ "on page", page, "ended up @", root.contentX + ", " + root.contentY)
+ }
+ onCurrentPageChanged: searchModel.currentPage = currentPage
+ }
+
+ Rectangle {
+ id: paper
+ width: rot90 ? image.height : image.width
+ height: rot90 ? image.width : image.height
+ property real rotationModulus: Math.abs(root.pageRotation % 180)
+ property bool rot90: rotationModulus > 45 && rotationModulus < 135
+
+ Image {
+ id: image
+ currentFrame: navigationStack.currentPage
+ source: document.status === PdfDocument.Ready ? document.source : ""
+ asynchronous: true
+ fillMode: Image.PreserveAspectFit
+ rotation: root.pageRotation
+ anchors.centerIn: parent
+ property real pageScale: image.paintedWidth / document.pagePointSize(navigationStack.currentPage).width
+
+ Shape {
+ anchors.fill: parent
+ visible: image.status === Image.Ready
+ ShapePath {
+ strokeWidth: -1
+ fillColor: style.pageSearchResultsColor
+ scale: Qt.size(image.pageScale, image.pageScale)
+ PathMultiline {
+ paths: searchModel.currentPageBoundingPolygons
+ }
+ }
+ ShapePath {
+ strokeWidth: style.currentSearchResultStrokeWidth
+ strokeColor: style.currentSearchResultStrokeColor
+ fillColor: "transparent"
+ scale: Qt.size(image.pageScale, image.pageScale)
+ PathMultiline {
+ paths: searchModel.currentResultBoundingPolygons
+ }
+ }
+ ShapePath {
+ fillColor: style.selectionColor
+ scale: Qt.size(image.pageScale, image.pageScale)
+ PathMultiline {
+ paths: selection.geometry
+ }
+ }
+ }
+
+ Repeater {
+ model: PdfLinkModel {
+ id: linkModel
+ document: root.document
+ page: navigationStack.currentPage
+ }
+ delegate: Shape {
+ x: rect.x * image.pageScale
+ y: rect.y * image.pageScale
+ width: rect.width * image.pageScale
+ height: rect.height * image.pageScale
+ ShapePath {
+ strokeWidth: style.linkUnderscoreStrokeWidth
+ strokeColor: style.linkUnderscoreColor
+ strokeStyle: style.linkUnderscoreStrokeStyle
+ dashPattern: style.linkUnderscoreDashPattern
+ startX: 0; startY: height
+ PathLine { x: width; y: height }
+ }
+ MouseArea { // TODO switch to TapHandler / HoverHandler in 5.15
+ anchors.fill: parent
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ if (page >= 0)
+ navigationStack.push(page, Qt.point(0, 0), root.renderScale)
+ else
+ Qt.openUrlExternally(url)
+ }
+ }
+ }
+ }
+ DragHandler {
+ id: textSelectionDrag
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ target: null
+ }
+ TapHandler {
+ id: tapHandler
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ }
+ }
+
+ PinchHandler {
+ id: pinch
+ minimumScale: 0.1
+ maximumScale: root.renderScale < 4 ? 2 : 1
+ minimumRotation: 0
+ maximumRotation: 0
+ enabled: image.sourceSize.width < 5000
+ onActiveChanged:
+ if (!active) {
+ var centroidInPoints = Qt.point(pinch.centroid.position.x / root.renderScale,
+ pinch.centroid.position.y / root.renderScale)
+ var centroidInFlickable = root.mapFromItem(paper, pinch.centroid.position.x, pinch.centroid.position.y)
+ var newSourceWidth = image.sourceSize.width * paper.scale
+ var ratio = newSourceWidth / image.sourceSize.width
+ if (root.debug)
+ console.log("pinch ended with centroid", pinch.centroid.position, centroidInPoints, "wrt flickable", centroidInFlickable,
+ "page at", paper.x.toFixed(2), paper.y.toFixed(2),
+ "contentX/Y were", root.contentX.toFixed(2), root.contentY.toFixed(2))
+ if (ratio > 1.1 || ratio < 0.9) {
+ var centroidOnPage = Qt.point(centroidInPoints.x * root.renderScale * ratio, centroidInPoints.y * root.renderScale * ratio)
+ paper.scale = 1
+ paper.x = 0
+ paper.y = 0
+ root.contentX = centroidOnPage.x - centroidInFlickable.x
+ root.contentY = centroidOnPage.y - centroidInFlickable.y
+ root.renderScale *= ratio // onRenderScaleChanged calls navigationStack.update() so we don't need to here
+ if (root.debug)
+ console.log("contentX/Y adjusted to", root.contentX.toFixed(2), root.contentY.toFixed(2))
+ } else {
+ paper.x = 0
+ paper.y = 0
+ }
+ }
+ grabPermissions: PointerHandler.CanTakeOverFromAnything
+ }
+ }
+}
diff --git a/src/pdf/quick/qml/PdfStyle.qml b/src/pdf/quick/qml/PdfStyle.qml
new file mode 100644
index 000000000..090465ce6
--- /dev/null
+++ b/src/pdf/quick/qml/PdfStyle.qml
@@ -0,0 +1,54 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQml 2.14
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Shapes 1.14
+
+QtObject {
+ property Control prototypeControl: Control { }
+ function withAlpha(color, alpha) {
+ return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha)
+ }
+ property color selectionColor: withAlpha(prototypeControl.palette.highlight, 0.5)
+ property color pageSearchResultsColor: "#80B0C4DE"
+ property color currentSearchResultStrokeColor: "cyan"
+ property real currentSearchResultStrokeWidth: 2
+ property color linkUnderscoreColor: prototypeControl.palette.link
+ property real linkUnderscoreStrokeWidth: 1
+ property var linkUnderscoreStrokeStyle: ShapePath.DashLine
+ property var linkUnderscoreDashPattern: [ 1, 4 ]
+}
diff --git a/src/pdf/quick/qmldir b/src/pdf/quick/qmldir
new file mode 100644
index 000000000..65fa95cda
--- /dev/null
+++ b/src/pdf/quick/qmldir
@@ -0,0 +1,4 @@
+module QtQuick.Pdf
+plugin pdfplugin
+classname QtQuick2PdfPlugin
+typeinfo plugins.qmltypes
diff --git a/src/pdf/quick/qquickpdfdocument.cpp b/src/pdf/quick/qquickpdfdocument.cpp
new file mode 100644
index 000000000..3d5f0fa10
--- /dev/null
+++ b/src/pdf/quick/qquickpdfdocument.cpp
@@ -0,0 +1,306 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpdfdocument_p.h"
+#include <QQuickItem>
+#include <QQmlEngine>
+#include <QStandardPaths>
+#include <private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PdfDocument
+ \instantiates QQuickPdfDocument
+ \inqmlmodule QtQuick.Pdf
+ \ingroup pdf
+ \brief A representation of a PDF document.
+ \since 5.15
+
+ PdfDocument provides access to PDF document meta-information.
+ It is not necessary for rendering, as it is enough to use an
+ \l Image with source set to the URL of the PDF.
+*/
+
+/*!
+ Constructs a PDF document.
+*/
+QQuickPdfDocument::QQuickPdfDocument(QObject *parent)
+ : QObject(parent)
+{
+ connect(&m_doc, &QPdfDocument::passwordChanged, this, &QQuickPdfDocument::passwordChanged);
+ connect(&m_doc, &QPdfDocument::passwordRequired, this, &QQuickPdfDocument::passwordRequired);
+ connect(&m_doc, &QPdfDocument::statusChanged, [=] (QPdfDocument::Status status) {
+ emit statusChanged();
+ if (status == QPdfDocument::Ready)
+ emit metaDataChanged();
+ });
+ connect(&m_doc, &QPdfDocument::pageCountChanged, this, &QQuickPdfDocument::pageCountChanged);
+}
+
+void QQuickPdfDocument::componentComplete()
+{
+ if (m_doc.error() == QPdfDocument::IncorrectPasswordError)
+ emit passwordRequired();
+}
+
+/*!
+ \qmlproperty url PdfDocument::source
+
+ This property holds a URL pointing to the PDF file to be loaded.
+
+ \note At this time, only local filesystem URLs are supported.
+*/
+void QQuickPdfDocument::setSource(QUrl source)
+{
+ if (m_source == source)
+ return;
+
+ m_source = source;
+ m_maxPageWidthHeight = QSizeF();
+ emit sourceChanged();
+ if (source.scheme() == QLatin1String("qrc"))
+ m_doc.load(QLatin1Char(':') + source.path());
+ else
+ m_doc.load(source.path());
+}
+
+/*!
+ \qmlproperty string PdfDocument::error
+
+ This property holds a translated string representation of the current
+ error, if any.
+
+ \sa status
+*/
+QString QQuickPdfDocument::error() const
+{
+ switch (m_doc.error()) {
+ case QPdfDocument::NoError:
+ return tr("no error");
+ break;
+ case QPdfDocument::UnknownError:
+ break;
+ case QPdfDocument::DataNotYetAvailableError:
+ return tr("data not yet available");
+ break;
+ case QPdfDocument::FileNotFoundError:
+ return tr("file not found");
+ break;
+ case QPdfDocument::InvalidFileFormatError:
+ return tr("invalid file format");
+ break;
+ case QPdfDocument::IncorrectPasswordError:
+ return tr("incorrect password");
+ break;
+ case QPdfDocument::UnsupportedSecuritySchemeError:
+ return tr("unsupported security scheme");
+ break;
+ }
+ return tr("unknown error");
+}
+
+/*!
+ \qmlproperty bool PdfDocument::password
+
+ This property holds the document password. If the passwordRequired()
+ signal is emitted, the UI should prompt the user and then set this
+ property so that document opening can continue.
+*/
+void QQuickPdfDocument::setPassword(const QString &password)
+{
+ if (m_doc.password() == password)
+ return;
+ m_doc.setPassword(password);
+ if (source().isValid() && source().isLocalFile())
+ m_doc.load(source().path());
+}
+
+/*!
+ \qmlproperty int PdfDocument::pageCount
+
+ This property holds the number of pages the PDF contains.
+*/
+
+/*!
+ \qmlsignal PdfDocument::passwordRequired()
+
+ This signal is emitted when the PDF requires a password in order to open.
+ The UI in a typical PDF viewer should prompt the user for the password
+ and then set the password property when the user has provided it.
+*/
+
+/*!
+ \qmlmethod size PdfDocument::pagePointSize(int page)
+
+ Returns the size of the given \a page in points.
+*/
+QSizeF QQuickPdfDocument::pagePointSize(int page) const
+{
+ return m_doc.pageSize(page);
+}
+
+qreal QQuickPdfDocument::maxPageWidth() const
+{
+ const_cast<QQuickPdfDocument *>(this)->updateMaxPageSize();
+ return m_maxPageWidthHeight.width();
+}
+
+qreal QQuickPdfDocument::maxPageHeight() const
+{
+ const_cast<QQuickPdfDocument *>(this)->updateMaxPageSize();
+ return m_maxPageWidthHeight.height();
+}
+
+/*!
+ \internal
+ \qmlmethod size PdfDocument::heightSumBeforePage(int page)
+
+ Returns the sum of the heights, in points, of all sets of \a facingPages
+ pages from 0 to the given \a page, exclusive.
+
+ That is, if the pages were laid out end-to-end in adjacent sets of
+ \a facingPages, what would be the distance in points from the top of the
+ first page to the top of the given page.
+*/
+// Workaround for lack of something analogous to ListView.positionViewAtIndex() in TableView
+qreal QQuickPdfDocument::heightSumBeforePage(int page, qreal spacing, int facingPages) const
+{
+ qreal ret = 0;
+ for (int i = 0; i < page; i+= facingPages) {
+ if (i + facingPages > page)
+ break;
+ qreal facingPagesHeight = 0;
+ for (int j = i; j < i + facingPages; ++j)
+ facingPagesHeight = qMax(facingPagesHeight, pagePointSize(j).height());
+ ret += facingPagesHeight + spacing;
+ }
+ return ret;
+}
+
+void QQuickPdfDocument::updateMaxPageSize()
+{
+ if (m_maxPageWidthHeight.isValid())
+ return;
+ qreal w = 0;
+ qreal h = 0;
+ const int count = pageCount();
+ for (int i = 0; i < count; ++i) {
+ auto size = pagePointSize(i);
+ w = qMax(w, size.width());
+ h = qMax(w, size.height());
+ }
+ m_maxPageWidthHeight = QSizeF(w, h);
+}
+
+/*!
+ \qmlproperty real PdfDocument::maxPageWidth
+
+ This property holds the width of the widest page in the document, in points.
+*/
+
+/*!
+ \qmlproperty real PdfDocument::maxPageHeight
+
+ This property holds the height of the tallest page in the document, in points.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::title
+
+ This property holds the document's title. A typical viewer UI can bind this
+ to the \c Window.title property.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::author
+
+ This property holds the name of the person who created the document.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::subject
+
+ This property holds the subject of the document.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::keywords
+
+ This property holds the keywords associated with the document.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::creator
+
+ If the document was converted to PDF from another format, this property
+ holds the name of the software that created the original document.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::producer
+
+ If the document was converted to PDF from another format, this property
+ holds the name of the software that converted it to PDF.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::creationDate
+
+ This property holds the date and time the document was created.
+*/
+
+/*!
+ \qmlproperty string PdfDocument::modificationDate
+
+ This property holds the date and time the document was most recently
+ modified.
+*/
+
+/*!
+ \qmlproperty enum PdfDocument::status
+
+ This property tells the current status of the document. The possible values are:
+
+ \value PdfDocument.Null The initial status after the document has been created or after it has been closed.
+ \value PdfDocument.Loading The status after load() has been called and before the document is fully loaded.
+ \value PdfDocument.Ready The status when the document is fully loaded and its data can be accessed.
+ \value PdfDocument.Unloading The status after close() has been called on an open document.
+ At this point the document is still valid and all its data can be accessed.
+ \value PdfDocument.Error The status after Loading, if loading has failed.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/pdf/quick/qquickpdfdocument_p.h b/src/pdf/quick/qquickpdfdocument_p.h
new file mode 100644
index 000000000..cefa4f756
--- /dev/null
+++ b/src/pdf/quick/qquickpdfdocument_p.h
@@ -0,0 +1,137 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPDFDOCUMENT_P_H
+#define QQUICKPDFDOCUMENT_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 <QtPdf/QPdfDocument>
+#include <QDateTime>
+#include <QJSValue>
+#include <QQmlParserStatus>
+#include <QUrl>
+#include <QVariant>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPdfDocument : public QObject, public QQmlParserStatus
+{
+ Q_OBJECT
+ Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged)
+ Q_PROPERTY(int pageCount READ pageCount NOTIFY pageCountChanged FINAL)
+ Q_PROPERTY(qreal maxPageWidth READ maxPageWidth NOTIFY metaDataChanged)
+ Q_PROPERTY(qreal maxPageHeight READ maxPageHeight NOTIFY metaDataChanged)
+ Q_PROPERTY(QString password READ password WRITE setPassword NOTIFY passwordChanged FINAL)
+ Q_PROPERTY(QPdfDocument::Status status READ status NOTIFY statusChanged FINAL)
+ Q_PROPERTY(QString error READ error NOTIFY statusChanged FINAL)
+
+ Q_PROPERTY(QString title READ title NOTIFY metaDataChanged)
+ Q_PROPERTY(QString subject READ subject NOTIFY metaDataChanged)
+ Q_PROPERTY(QString author READ author NOTIFY metaDataChanged)
+ Q_PROPERTY(QString keywords READ keywords NOTIFY metaDataChanged)
+ Q_PROPERTY(QString producer READ producer NOTIFY metaDataChanged)
+ Q_PROPERTY(QString creator READ creator NOTIFY metaDataChanged)
+ Q_PROPERTY(QDateTime creationDate READ creationDate NOTIFY metaDataChanged)
+ Q_PROPERTY(QDateTime modificationDate READ modificationDate NOTIFY metaDataChanged)
+
+public:
+ explicit QQuickPdfDocument(QObject *parent = nullptr);
+
+ void classBegin() override {}
+ void componentComplete() override;
+
+ QUrl source() const { return m_source; }
+ void setSource(QUrl source);
+
+ int pageCount() const { return m_doc.pageCount(); }
+ QPdfDocument::Status status() const { return m_doc.status(); }
+
+ QString error() const;
+
+ QString password() const { return m_doc.password(); }
+ void setPassword(const QString &password);
+
+ QString title() { return m_doc.metaData(QPdfDocument::Title).toString(); }
+ QString author() { return m_doc.metaData(QPdfDocument::Author).toString(); }
+ QString subject() { return m_doc.metaData(QPdfDocument::Subject).toString(); }
+ QString keywords() { return m_doc.metaData(QPdfDocument::Keywords).toString(); }
+ QString producer() { return m_doc.metaData(QPdfDocument::Producer).toString(); }
+ QString creator() { return m_doc.metaData(QPdfDocument::Creator).toString(); }
+ QDateTime creationDate() { return m_doc.metaData(QPdfDocument::CreationDate).toDateTime(); }
+ QDateTime modificationDate() { return m_doc.metaData(QPdfDocument::ModificationDate).toDateTime(); }
+
+ Q_INVOKABLE QSizeF pagePointSize(int page) const;
+ qreal maxPageWidth() const;
+ qreal maxPageHeight() const;
+ Q_INVOKABLE qreal heightSumBeforePage(int page, qreal spacing = 0, int facingPages = 1) const;
+
+Q_SIGNALS:
+ void sourceChanged();
+ void passwordChanged();
+ void passwordRequired();
+ void statusChanged();
+ void pageCountChanged();
+ void metaDataChanged();
+
+private:
+ QPdfDocument &document() { return m_doc; }
+ void updateMaxPageSize();
+
+private:
+ QUrl m_source;
+ QPdfDocument m_doc;
+ QSizeF m_maxPageWidthHeight;
+
+ friend class QQuickPdfLinkModel;
+ friend class QQuickPdfSearchModel;
+ friend class QQuickPdfSelection;
+
+ Q_DISABLE_COPY(QQuickPdfDocument)
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPDFDOCUMENT_P_H
diff --git a/src/pdf/quick/qquickpdflinkmodel.cpp b/src/pdf/quick/qquickpdflinkmodel.cpp
new file mode 100644
index 000000000..f2ff3fd22
--- /dev/null
+++ b/src/pdf/quick/qquickpdflinkmodel.cpp
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpdflinkmodel_p.h"
+#include <QQuickItem>
+#include <QQmlEngine>
+#include <QStandardPaths>
+#include <private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PdfLinkModel
+ \instantiates QQuickPdfLinkModel
+ \inqmlmodule QtQuick.Pdf
+ \ingroup pdf
+ \brief A representation of links within a PDF document.
+ \since 5.15
+
+ PdfLinkModel provides the geometry and the destination for each link
+ that the specified \l page contains.
+
+ The available model roles are:
+
+ \value rect
+ Bounding rectangle around the link.
+ \value url
+ If the link is a web link, the URL for that; otherwise an empty URL.
+ \value page
+ If the link is an internal link, the page number to which the link should jump; otherwise \c {-1}.
+ \value location
+ If the link is an internal link, the location on the page to which the link should jump.
+ \value zoom
+ If the link is an internal link, the intended zoom level on the destination page.
+
+ Normally it will be used with \l {QtQuick::Repeater}{Repeater} to visualize
+ the links and provide the ability to click them:
+
+ \qml
+ Repeater {
+ model: PdfLinkModel {
+ document: root.document
+ page: image.currentFrame
+ }
+ delegate: Rectangle {
+ color: "transparent"
+ border.color: "lightgrey"
+ x: rect.x
+ y: rect.y
+ width: rect.width
+ height: rect.height
+ HoverHandler { cursorShape: Qt.PointingHandCursor }
+ TapHandler {
+ onTapped: {
+ if (page >= 0)
+ image.currentFrame = page
+ else
+ Qt.openUrlExternally(url)
+ }
+ }
+ }
+ }
+ \endqml
+
+ \note General-purpose PDF viewing capabilities are provided by
+ \l PdfScrollablePageView and \l PdfMultiPageView. PdfLinkModel is only needed
+ when building PDF view components from scratch.
+*/
+
+QQuickPdfLinkModel::QQuickPdfLinkModel(QObject *parent)
+ : QPdfLinkModel(parent)
+{
+}
+
+/*!
+ \qmlproperty PdfDocument PdfLinkModel::document
+
+ This property holds the PDF document in which links are to be found.
+*/
+QQuickPdfDocument *QQuickPdfLinkModel::document() const
+{
+ return m_quickDocument;
+}
+
+void QQuickPdfLinkModel::setDocument(QQuickPdfDocument *document)
+{
+ if (document == m_quickDocument)
+ return;
+ m_quickDocument = document;
+ QPdfLinkModel::setDocument(&document->m_doc);
+}
+
+/*!
+ \qmlproperty int PdfLinkModel::page
+
+ This property holds the page number on which links are to be found.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/pdf/quick/qquickpdflinkmodel_p.h b/src/pdf/quick/qquickpdflinkmodel_p.h
new file mode 100644
index 000000000..23ad6c8c1
--- /dev/null
+++ b/src/pdf/quick/qquickpdflinkmodel_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPDFLINKMODEL_P_H
+#define QQUICKPDFLINKMODEL_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 "qquickpdfdocument_p.h"
+#include "../api/qpdflinkmodel_p.h"
+
+#include <QVariant>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPdfLinkModel : public QPdfLinkModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged)
+
+public:
+ explicit QQuickPdfLinkModel(QObject *parent = nullptr);
+
+ QQuickPdfDocument *document() const;
+ void setDocument(QQuickPdfDocument *document);
+
+signals:
+ void documentChanged();
+
+private:
+ void updateResults();
+
+private:
+ QQuickPdfDocument *m_quickDocument;
+ QVector<QPolygonF> m_linksGeometry;
+
+ Q_DISABLE_COPY(QQuickPdfLinkModel)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPdfLinkModel)
+
+#endif // QQUICKPDFLINKMODEL_P_H
diff --git a/src/pdf/quick/qquickpdfnavigationstack.cpp b/src/pdf/quick/qquickpdfnavigationstack.cpp
new file mode 100644
index 000000000..7ba317557
--- /dev/null
+++ b/src/pdf/quick/qquickpdfnavigationstack.cpp
@@ -0,0 +1,266 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpdfnavigationstack_p.h"
+#include <QLoggingCategory>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcNav, "qt.pdf.navigationstack")
+
+/*!
+ \qmltype PdfNavigationStack
+ \instantiates QQuickPdfNavigationStack
+ \inqmlmodule QtQuick.Pdf
+ \ingroup pdf
+ \brief History of the destinations visited within a PDF Document.
+ \since 5.15
+
+ PdfNavigationStack remembers which destinations the user has visited in a PDF
+ document, and provides the ability to traverse backward and forward.
+*/
+
+QQuickPdfNavigationStack::QQuickPdfNavigationStack(QObject *parent)
+ : QObject(parent)
+{
+ push(0, QPointF(), 1);
+}
+
+/*!
+ \qmlmethod void PdfNavigationStack::forward()
+
+ Goes back to the page, location and zoom level that was being viewed before
+ back() was called, and then emits the \l jumped() signal.
+
+ If a new destination was pushed since the last time \l back() was called,
+ the forward() function does nothing, because there is a branch in the
+ timeline which causes the "future" to be lost.
+*/
+void QQuickPdfNavigationStack::forward()
+{
+ if (m_currentHistoryIndex >= m_pageHistory.count() - 1)
+ return;
+ bool backAvailableWas = backAvailable();
+ bool forwardAvailableWas = forwardAvailable();
+ QPointF currentLocationWas = currentLocation();
+ qreal currentZoomWas = currentZoom();
+ ++m_currentHistoryIndex;
+ m_changing = true;
+ emit jumped(currentPage(), currentLocation(), currentZoom());
+ if (currentZoomWas != currentZoom())
+ emit currentZoomChanged();
+ emit currentPageChanged();
+ if (currentLocationWas != currentLocation())
+ emit currentLocationChanged();
+ if (!backAvailableWas)
+ emit backAvailableChanged();
+ if (forwardAvailableWas != forwardAvailable())
+ emit forwardAvailableChanged();
+ m_changing = false;
+}
+
+/*!
+ \qmlmethod void PdfNavigationStack::back()
+
+ Pops the stack, updates the \l currentPage, \l currentLocation and
+ \l currentZoom properties to the most-recently-viewed destination, and then
+ emits the \l jumped() signal.
+*/
+void QQuickPdfNavigationStack::back()
+{
+ if (m_currentHistoryIndex <= 0)
+ return;
+ bool backAvailableWas = backAvailable();
+ bool forwardAvailableWas = forwardAvailable();
+ QPointF currentLocationWas = currentLocation();
+ qreal currentZoomWas = currentZoom();
+ --m_currentHistoryIndex;
+ m_changing = true;
+ emit jumped(currentPage(), currentLocation(), currentZoom());
+ if (currentZoomWas != currentZoom())
+ emit currentZoomChanged();
+ emit currentPageChanged();
+ if (currentLocationWas != currentLocation())
+ emit currentLocationChanged();
+ if (backAvailableWas != backAvailable())
+ emit backAvailableChanged();
+ if (!forwardAvailableWas)
+ emit forwardAvailableChanged();
+ m_changing = false;
+}
+
+/*!
+ \qmlproperty int PdfNavigationStack::currentPage
+
+ This property holds the current page that is being viewed.
+ If there is no current page, it holds \c -1.
+*/
+int QQuickPdfNavigationStack::currentPage() const
+{
+ if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count())
+ return -1;
+ return m_pageHistory.at(m_currentHistoryIndex)->page;
+}
+
+/*!
+ \qmlproperty point PdfNavigationStack::currentLocation
+
+ This property holds the current location on the page that is being viewed.
+*/
+QPointF QQuickPdfNavigationStack::currentLocation() const
+{
+ if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count())
+ return QPointF();
+ return m_pageHistory.at(m_currentHistoryIndex)->location;
+}
+
+/*!
+ \qmlproperty real PdfNavigationStack::currentZoom
+
+ This property holds the magnification scale on the page that is being viewed.
+*/
+qreal QQuickPdfNavigationStack::currentZoom() const
+{
+ if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count())
+ return 1;
+ return m_pageHistory.at(m_currentHistoryIndex)->zoom;
+}
+
+/*!
+ \qmlmethod void PdfNavigationStack::push(int page, point location, qreal zoom)
+
+ Adds the given destination, consisting of \a page, \a location and \a zoom,
+ to the history of visited locations.
+
+ If forwardAvailable is \c true, calling this function represents a branch
+ in the timeline which causes the "future" to be lost, and therefore
+ forwardAvailable will change to \c false.
+*/
+void QQuickPdfNavigationStack::push(int page, QPointF location, qreal zoom)
+{
+ if (page == currentPage() && location == currentLocation() && zoom == currentZoom())
+ return;
+ if (qFuzzyIsNull(zoom))
+ zoom = currentZoom();
+ bool backAvailableWas = backAvailable();
+ bool forwardAvailableWas = forwardAvailable();
+ if (!m_changing) {
+ if (m_currentHistoryIndex >= 0 && forwardAvailableWas)
+ m_pageHistory.remove(m_currentHistoryIndex + 1, m_pageHistory.count() - m_currentHistoryIndex - 1);
+ m_pageHistory.append(QExplicitlySharedDataPointer<QPdfDestinationPrivate>(new QPdfDestinationPrivate(page, location, zoom)));
+ m_currentHistoryIndex = m_pageHistory.count() - 1;
+ }
+ emit currentZoomChanged();
+ emit currentPageChanged();
+ emit currentLocationChanged();
+ if (m_changing)
+ return;
+ if (!backAvailableWas)
+ emit backAvailableChanged();
+ if (forwardAvailableWas)
+ emit forwardAvailableChanged();
+ emit jumped(page, location, zoom);
+ qCDebug(qLcNav) << "push: index" << m_currentHistoryIndex << "page" << page
+ << "@" << location << "zoom" << zoom << "-> history" <<
+ [this]() {
+ QStringList ret;
+ for (auto d : m_pageHistory)
+ ret << QString::number(d->page);
+ return ret.join(',');
+ }();
+}
+
+/*!
+ \qmlmethod void PdfNavigationStack::update(int page, point location, qreal zoom)
+
+ Modifies the current destination, consisting of \a page, \a location and \a zoom.
+
+ This can be called periodically while the user is manually moving around
+ the document, so that after back() is called, forward() will jump back to
+ the most-recently-viewed destination rather than the destination that was
+ last specified by push().
+
+ The \c currentZoomChanged, \c currentPageChanged and \c currentLocationChanged
+ signals will be emitted if the respective properties are actually changed.
+ The \l jumped signal is not emitted, because this operation
+ represents smooth movement rather than a navigational jump.
+*/
+void QQuickPdfNavigationStack::update(int page, QPointF location, qreal zoom)
+{
+ if (m_currentHistoryIndex < 0 || m_currentHistoryIndex >= m_pageHistory.count())
+ return;
+ int currentPageWas = currentPage();
+ QPointF currentLocationWas = currentLocation();
+ qreal currentZoomWas = currentZoom();
+ if (page == currentPageWas && location == currentLocationWas && zoom == currentZoomWas)
+ return;
+ m_pageHistory[m_currentHistoryIndex]->page = page;
+ m_pageHistory[m_currentHistoryIndex]->location = location;
+ m_pageHistory[m_currentHistoryIndex]->zoom = zoom;
+ if (currentZoomWas != zoom)
+ emit currentZoomChanged();
+ if (currentPageWas != page)
+ emit currentPageChanged();
+ if (currentLocationWas != location)
+ emit currentLocationChanged();
+ qCDebug(qLcNav) << "update: index" << m_currentHistoryIndex << "page" << page
+ << "@" << location << "zoom" << zoom << "-> history" <<
+ [this]() {
+ QStringList ret;
+ for (auto d : m_pageHistory)
+ ret << QString::number(d->page);
+ return ret.join(',');
+ }();
+}
+
+bool QQuickPdfNavigationStack::backAvailable() const
+{
+ return m_currentHistoryIndex > 0;
+}
+
+bool QQuickPdfNavigationStack::forwardAvailable() const
+{
+ return m_currentHistoryIndex < m_pageHistory.count() - 1;
+}
+
+/*!
+ \qmlsignal PdfNavigationStack::jumped(int page, point location, qreal zoom)
+
+ This signal is emitted when forward(), back() or push() is called, but not
+ when update() is called.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/pdf/quick/qquickpdfnavigationstack_p.h b/src/pdf/quick/qquickpdfnavigationstack_p.h
new file mode 100644
index 000000000..8d7102fb1
--- /dev/null
+++ b/src/pdf/quick/qquickpdfnavigationstack_p.h
@@ -0,0 +1,102 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPDFNAVIGATIONSTACK_P_H
+#define QQUICKPDFNAVIGATIONSTACK_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 "qquickpdfdocument_p.h"
+#include "../api/qpdfdestination_p.h"
+
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPdfNavigationStack : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(int currentPage READ currentPage NOTIFY currentPageChanged)
+ Q_PROPERTY(QPointF currentLocation READ currentLocation NOTIFY currentLocationChanged)
+ Q_PROPERTY(qreal currentZoom READ currentZoom NOTIFY currentZoomChanged)
+ Q_PROPERTY(bool backAvailable READ backAvailable NOTIFY backAvailableChanged)
+ Q_PROPERTY(bool forwardAvailable READ forwardAvailable NOTIFY forwardAvailableChanged)
+
+public:
+ explicit QQuickPdfNavigationStack(QObject *parent = nullptr);
+
+ Q_INVOKABLE void push(int page, QPointF location, qreal zoom);
+ Q_INVOKABLE void update(int page, QPointF location, qreal zoom);
+ Q_INVOKABLE void forward();
+ Q_INVOKABLE void back();
+
+ int currentPage() const;
+ QPointF currentLocation() const;
+ qreal currentZoom() const;
+
+ bool backAvailable() const;
+ bool forwardAvailable() const;
+
+Q_SIGNALS:
+ void currentPageChanged();
+ void currentLocationChanged();
+ void currentZoomChanged();
+ void backAvailableChanged();
+ void forwardAvailableChanged();
+ void jumped(int page, QPointF location, qreal zoom);
+
+private:
+ QVector<QExplicitlySharedDataPointer<QPdfDestinationPrivate>> m_pageHistory;
+ int m_currentHistoryIndex = 0;
+ bool m_changing = false;
+
+ Q_DISABLE_COPY(QQuickPdfNavigationStack)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPdfNavigationStack)
+
+#endif // QQUICKPDFNAVIGATIONSTACK_P_H
diff --git a/src/pdf/quick/qquickpdfsearchmodel.cpp b/src/pdf/quick/qquickpdfsearchmodel.cpp
new file mode 100644
index 000000000..a4b457841
--- /dev/null
+++ b/src/pdf/quick/qquickpdfsearchmodel.cpp
@@ -0,0 +1,277 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpdfsearchmodel_p.h"
+#include <QtCore/qloggingcategory.h>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcS, "qt.pdf.search")
+
+/*!
+ \qmltype PdfSearchModel
+ \instantiates QQuickPdfSearchModel
+ \inqmlmodule QtQuick.Pdf
+ \ingroup pdf
+ \brief A representation of text search results within a PDF Document.
+ \since 5.15
+
+ PdfSearchModel provides the ability to search for text strings within a
+ document and get the geometric locations of matches on each page.
+*/
+
+QQuickPdfSearchModel::QQuickPdfSearchModel(QObject *parent)
+ : QPdfSearchModel(parent)
+{
+ connect(this, &QPdfSearchModel::searchStringChanged,
+ this, &QQuickPdfSearchModel::onResultsChanged);
+}
+
+QQuickPdfDocument *QQuickPdfSearchModel::document() const
+{
+ return m_quickDocument;
+}
+
+void QQuickPdfSearchModel::setDocument(QQuickPdfDocument *document)
+{
+ if (document == m_quickDocument || !document)
+ return;
+
+ m_quickDocument = document;
+ QPdfSearchModel::setDocument(&document->m_doc);
+}
+
+/*!
+ \qmlproperty list<list<point>> PdfSearchModel::currentResultBoundingPolygons
+
+ A set of paths in a form that can be bound to the \c paths property of a
+ \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of
+ rectangles around the regions comprising the search result \l currentResult
+ on \l currentPage. This is normally used to highlight one search result
+ at a time, in a UI that allows stepping through the results:
+
+ \qml
+ PdfDocument {
+ id: doc
+ }
+ PdfSearchModel {
+ id: searchModel
+ document: doc
+ currentPage: view.currentPage
+ currentResult: ...
+ }
+ Shape {
+ ShapePath {
+ PathMultiline {
+ paths: searchModel.currentResultBoundingPolygons
+ }
+ }
+ }
+ \endqml
+
+ \sa PathMultiline
+*/
+QVector<QPolygonF> QQuickPdfSearchModel::currentResultBoundingPolygons() const
+{
+ QVector<QPolygonF> ret;
+ const auto &results = const_cast<QQuickPdfSearchModel *>(this)->resultsOnPage(m_currentPage);
+ if (m_currentResult < 0 || m_currentResult >= results.count())
+ return ret;
+ const auto result = results[m_currentResult];
+ for (auto rect : result.rectangles())
+ ret << QPolygonF(rect);
+ return ret;
+}
+
+void QQuickPdfSearchModel::onResultsChanged()
+{
+ emit currentPageBoundingPolygonsChanged();
+ emit currentResultBoundingPolygonsChanged();
+}
+
+/*!
+ \qmlproperty list<list<point>> PdfSearchModel::currentPageBoundingPolygons
+
+ A set of paths in a form that can be bound to the \c paths property of a
+ \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of
+ rectangles around all the regions where search results are found on
+ \l currentPage:
+
+ \qml
+ PdfDocument {
+ id: doc
+ }
+ PdfSearchModel {
+ id: searchModel
+ document: doc
+ }
+ Shape {
+ ShapePath {
+ PathMultiline {
+ paths: searchModel.matchGeometry(view.currentPage)
+ }
+ }
+ }
+ \endqml
+
+ \sa PathMultiline
+*/
+QVector<QPolygonF> QQuickPdfSearchModel::currentPageBoundingPolygons() const
+{
+ return const_cast<QQuickPdfSearchModel *>(this)->boundingPolygonsOnPage(m_currentPage);
+}
+
+/*!
+ \qmlfunction list<list<point>> PdfSearchModel::boundingPolygonsOnPage(int page)
+
+ Returns a set of paths in a form that can be bound to the \c paths property of a
+ \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of
+ rectangles around all the locations where search results are found:
+
+ \qml
+ PdfDocument {
+ id: doc
+ }
+ PdfSearchModel {
+ id: searchModel
+ document: doc
+ }
+ Shape {
+ ShapePath {
+ PathMultiline {
+ paths: searchModel.matchGeometry(view.currentPage)
+ }
+ }
+ }
+ \endqml
+
+ \sa PathMultiline
+*/
+QVector<QPolygonF> QQuickPdfSearchModel::boundingPolygonsOnPage(int page)
+{
+ if (!document() || searchString().isEmpty() || page < 0 || page > document()->pageCount())
+ return {};
+
+ updatePage(page);
+
+ QVector<QPolygonF> ret;
+ auto m = QPdfSearchModel::resultsOnPage(page);
+ for (auto result : m) {
+ for (auto rect : result.rectangles())
+ ret << QPolygonF(rect);
+ }
+
+ return ret;
+}
+
+/*!
+ \qmlproperty int PdfSearchModel::currentPage
+
+ The page on which \l currentMatchGeometry should provide filtered search results.
+*/
+void QQuickPdfSearchModel::setCurrentPage(int currentPage)
+{
+ if (m_currentPage == currentPage)
+ return;
+
+ if (currentPage < 0)
+ currentPage = document()->pageCount() - 1;
+ else if (currentPage >= document()->pageCount())
+ currentPage = 0;
+
+ m_currentPage = currentPage;
+ if (!m_suspendSignals) {
+ emit currentPageChanged();
+ onResultsChanged();
+ }
+}
+
+/*!
+ \qmlproperty int PdfSearchModel::currentResult
+
+ The result index on \l currentPage for which \l currentResultBoundingPolygons
+ should provide the regions to highlight.
+*/
+void QQuickPdfSearchModel::setCurrentResult(int currentResult)
+{
+ if (m_currentResult == currentResult)
+ return;
+
+ int currentResultWas = currentResult;
+ int currentPageWas = m_currentPage;
+ if (currentResult < 0) {
+ setCurrentPage(m_currentPage - 1);
+ while (resultsOnPage(m_currentPage).count() == 0 && m_currentPage != currentPageWas) {
+ m_suspendSignals = true;
+ setCurrentPage(m_currentPage - 1);
+ }
+ if (m_suspendSignals) {
+ emit currentPageChanged();
+ m_suspendSignals = false;
+ }
+ const auto results = resultsOnPage(m_currentPage);
+ currentResult = results.count() - 1;
+ } else {
+ const auto results = resultsOnPage(m_currentPage);
+ if (currentResult >= results.count()) {
+ setCurrentPage(m_currentPage + 1);
+ while (resultsOnPage(m_currentPage).count() == 0 && m_currentPage != currentPageWas) {
+ m_suspendSignals = true;
+ setCurrentPage(m_currentPage + 1);
+ }
+ if (m_suspendSignals) {
+ emit currentPageChanged();
+ m_suspendSignals = false;
+ }
+ currentResult = 0;
+ }
+ }
+ qCDebug(qLcS) << "currentResult was" << m_currentResult
+ << "requested" << currentResultWas << "on page" << currentPageWas
+ << "->" << currentResult << "on page" << m_currentPage;
+
+ m_currentResult = currentResult;
+ emit currentResultChanged();
+ emit currentResultBoundingPolygonsChanged();
+}
+
+/*!
+ \qmlproperty string PdfSearchModel::searchString
+
+ The string to search for.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/pdf/quick/qquickpdfsearchmodel_p.h b/src/pdf/quick/qquickpdfsearchmodel_p.h
new file mode 100644
index 000000000..3e05f80e3
--- /dev/null
+++ b/src/pdf/quick/qquickpdfsearchmodel_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPDFSEARCHMODEL_P_H
+#define QQUICKPDFSEARCHMODEL_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 "qquickpdfdocument_p.h"
+#include "../api/qpdfsearchmodel.h"
+
+#include <QtCore/qvariant.h>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPdfSearchModel : public QPdfSearchModel
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(int currentPage READ currentPage WRITE setCurrentPage NOTIFY currentPageChanged)
+ Q_PROPERTY(int currentResult READ currentResult WRITE setCurrentResult NOTIFY currentResultChanged)
+ Q_PROPERTY(QVector<QPolygonF> currentPageBoundingPolygons READ currentPageBoundingPolygons NOTIFY currentPageBoundingPolygonsChanged)
+ Q_PROPERTY(QVector<QPolygonF> currentResultBoundingPolygons READ currentResultBoundingPolygons NOTIFY currentResultBoundingPolygonsChanged)
+
+public:
+ explicit QQuickPdfSearchModel(QObject *parent = nullptr);
+
+ QQuickPdfDocument *document() const;
+ void setDocument(QQuickPdfDocument * document);
+
+ Q_INVOKABLE QVector<QPolygonF> boundingPolygonsOnPage(int page);
+
+ int currentPage() const { return m_currentPage; }
+ void setCurrentPage(int currentPage);
+
+ int currentResult() const { return m_currentResult; }
+ void setCurrentResult(int currentResult);
+
+ QVector<QPolygonF> currentPageBoundingPolygons() const;
+ QVector<QPolygonF> currentResultBoundingPolygons() const;
+
+signals:
+ void documentChanged();
+ void currentPageChanged();
+ void currentResultChanged();
+ void currentPageBoundingPolygonsChanged();
+ void currentResultBoundingPolygonsChanged();
+
+private:
+ void updateResults();
+ void onResultsChanged();
+
+private:
+ QQuickPdfDocument *m_quickDocument = nullptr;
+ int m_currentPage = 0;
+ int m_currentResult = 0;
+ bool m_suspendSignals = false;
+
+ Q_DISABLE_COPY(QQuickPdfSearchModel)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPdfSearchModel)
+QML_DECLARE_TYPE(QPdfSelection)
+
+#endif // QQUICKPDFSEARCHMODEL_P_H
diff --git a/src/pdf/quick/qquickpdfselection.cpp b/src/pdf/quick/qquickpdfselection.cpp
new file mode 100644
index 000000000..5371e85e5
--- /dev/null
+++ b/src/pdf/quick/qquickpdfselection.cpp
@@ -0,0 +1,284 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpdfselection_p.h"
+#include "qquickpdfdocument_p.h"
+#include <QClipboard>
+#include <QQuickItem>
+#include <QQmlEngine>
+#include <QStandardPaths>
+#include <private/qguiapplication_p.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype PdfSelection
+ \instantiates QQuickPdfSelection
+ \inqmlmodule QtQuick.Pdf
+ \ingroup pdf
+ \brief A representation of a text selection within a PDF Document.
+ \since 5.15
+
+ PdfSelection provides the text string and its geometry within a bounding box
+ from one point to another.
+*/
+
+/*!
+ Constructs a SearchModel.
+*/
+QQuickPdfSelection::QQuickPdfSelection(QObject *parent)
+ : QObject(parent)
+{
+}
+
+QQuickPdfDocument *QQuickPdfSelection::document() const
+{
+ return m_document;
+}
+
+void QQuickPdfSelection::setDocument(QQuickPdfDocument *document)
+{
+ if (m_document == document)
+ return;
+
+ if (m_document) {
+ disconnect(m_document, &QQuickPdfDocument::sourceChanged,
+ this, &QQuickPdfSelection::resetPoints);
+ }
+ m_document = document;
+ emit documentChanged();
+ resetPoints();
+ connect(m_document, &QQuickPdfDocument::sourceChanged,
+ this, &QQuickPdfSelection::resetPoints);
+}
+
+/*!
+ \qmlproperty list<list<point>> PdfSelection::geometry
+
+ A set of paths in a form that can be bound to the \c paths property of a
+ \l {QtQuick::PathMultiline}{PathMultiline} instance to render a batch of
+ rectangles around the text regions that are included in the selection:
+
+ \qml
+ PdfDocument {
+ id: doc
+ }
+ PdfSelection {
+ id: selection
+ document: doc
+ fromPoint: textSelectionDrag.centroid.pressPosition
+ toPoint: textSelectionDrag.centroid.position
+ hold: !textSelectionDrag.active
+ }
+ Shape {
+ ShapePath {
+ PathMultiline {
+ paths: selection.geometry
+ }
+ }
+ }
+ DragHandler {
+ id: textSelectionDrag
+ acceptedDevices: PointerDevice.Mouse | PointerDevice.Stylus
+ target: null
+ }
+ \endqml
+
+ \sa PathMultiline
+*/
+QVector<QPolygonF> QQuickPdfSelection::geometry() const
+{
+ return m_geometry;
+}
+
+void QQuickPdfSelection::selectAll()
+{
+ QPdfSelection sel = m_document->m_doc.getAllText(m_page);
+ if (sel.text() != m_text) {
+ m_text = sel.text();
+ if (QGuiApplication::clipboard()->supportsSelection())
+ sel.copyToClipboard(QClipboard::Selection);
+ emit textChanged();
+ }
+
+ if (sel.bounds() != m_geometry) {
+ m_geometry = sel.bounds();
+ emit geometryChanged();
+ }
+}
+
+void QQuickPdfSelection::resetPoints()
+{
+ bool wasHolding = m_hold;
+ m_hold = false;
+ setFromPoint(QPointF());
+ setToPoint(QPointF());
+ m_hold = wasHolding;
+}
+
+/*!
+ \qmlproperty int PdfSelection::page
+
+ The page number on which to search.
+
+ \sa QtQuick::Image::currentFrame
+*/
+int QQuickPdfSelection::page() const
+{
+ return m_page;
+}
+
+void QQuickPdfSelection::setPage(int page)
+{
+ if (m_page == page)
+ return;
+
+ m_page = page;
+ emit pageChanged();
+ resetPoints();
+}
+
+/*!
+ \qmlproperty point PdfSelection::fromPoint
+
+ The beginning location, in \l {https://en.wikipedia.org/wiki/Point_(typography)}{points}
+ from the upper-left corner of the page, from which to find selected text.
+ This can be bound to a scaled version of the \c centroid.pressPosition
+ of a \l DragHandler to begin selecting text from the position where the user
+ presses the mouse button and begins dragging, for example.
+*/
+QPointF QQuickPdfSelection::fromPoint() const
+{
+ return m_fromPoint;
+}
+
+void QQuickPdfSelection::setFromPoint(QPointF fromPoint)
+{
+ if (m_hold || m_fromPoint == fromPoint)
+ return;
+
+ m_fromPoint = fromPoint;
+ emit fromPointChanged();
+ updateResults();
+}
+
+/*!
+ \qmlproperty point PdfSelection::toPoint
+
+ The ending location, in \l {https://en.wikipedia.org/wiki/Point_(typography)}{points}
+ from the upper-left corner of the page, from which to find selected text.
+ This can be bound to a scaled version of the \c centroid.position
+ of a \l DragHandler to end selection of text at the position where the user
+ is currently dragging the mouse, for example.
+*/
+QPointF QQuickPdfSelection::toPoint() const
+{
+ return m_toPoint;
+}
+
+void QQuickPdfSelection::setToPoint(QPointF toPoint)
+{
+ if (m_hold || m_toPoint == toPoint)
+ return;
+
+ m_toPoint = toPoint;
+ emit toPointChanged();
+ updateResults();
+}
+
+/*!
+ \qmlproperty bool PdfSelection::hold
+
+ Controls whether to hold the existing selection regardless of changes to
+ \l fromPoint and \l toPoint. This property can be set to \c true when the mouse
+ or touchpoint is released, so that the selection is not lost due to the
+ point bindings changing.
+*/
+bool QQuickPdfSelection::hold() const
+{
+ return m_hold;
+}
+
+void QQuickPdfSelection::setHold(bool hold)
+{
+ if (m_hold == hold)
+ return;
+
+ m_hold = hold;
+ emit holdChanged();
+}
+
+/*!
+ \qmlproperty string PdfSelection::string
+
+ The string found.
+*/
+QString QQuickPdfSelection::text() const
+{
+ return m_text;
+}
+
+#if QT_CONFIG(clipboard)
+/*!
+ \qmlmethod void PdfSelection::copyToClipboard()
+
+ Copies plain text from the \l string property to the system clipboard.
+*/
+void QQuickPdfSelection::copyToClipboard() const
+{
+ QGuiApplication::clipboard()->setText(m_text);
+}
+#endif
+
+void QQuickPdfSelection::updateResults()
+{
+ if (!m_document)
+ return;
+ QPdfSelection sel = m_document->document().getSelection(m_page, m_fromPoint, m_toPoint);
+ if (sel.text() != m_text) {
+ m_text = sel.text();
+ if (QGuiApplication::clipboard()->supportsSelection())
+ sel.copyToClipboard(QClipboard::Selection);
+ emit textChanged();
+ }
+
+ if (sel.bounds() != m_geometry) {
+ m_geometry = sel.bounds();
+ emit geometryChanged();
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/pdf/quick/qquickpdfselection_p.h b/src/pdf/quick/qquickpdfselection_p.h
new file mode 100644
index 000000000..bb4a50fed
--- /dev/null
+++ b/src/pdf/quick/qquickpdfselection_p.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPDFSELECTION_P_H
+#define QQUICKPDFSELECTION_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 <QPointF>
+#include <QPolygonF>
+#include <QVariant>
+#include <QtQml/qqml.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickPdfDocument;
+
+class QQuickPdfSelection : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickPdfDocument *document READ document WRITE setDocument NOTIFY documentChanged)
+ Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
+ Q_PROPERTY(QPointF fromPoint READ fromPoint WRITE setFromPoint NOTIFY fromPointChanged)
+ Q_PROPERTY(QPointF toPoint READ toPoint WRITE setToPoint NOTIFY toPointChanged)
+ Q_PROPERTY(bool hold READ hold WRITE setHold NOTIFY holdChanged)
+
+ Q_PROPERTY(QString text READ text NOTIFY textChanged)
+ Q_PROPERTY(QVector<QPolygonF> geometry READ geometry NOTIFY geometryChanged)
+
+public:
+ explicit QQuickPdfSelection(QObject *parent = nullptr);
+
+ QQuickPdfDocument *document() const;
+ void setDocument(QQuickPdfDocument * document);
+ int page() const;
+ void setPage(int page);
+ QPointF fromPoint() const;
+ void setFromPoint(QPointF fromPoint);
+ QPointF toPoint() const;
+ void setToPoint(QPointF toPoint);
+ bool hold() const;
+ void setHold(bool hold);
+
+ QString text() const;
+ QVector<QPolygonF> geometry() const;
+
+ Q_INVOKABLE void selectAll();
+#if QT_CONFIG(clipboard)
+ Q_INVOKABLE void copyToClipboard() const;
+#endif
+
+signals:
+ void documentChanged();
+ void pageChanged();
+ void fromPointChanged();
+ void toPointChanged();
+ void holdChanged();
+ void textChanged();
+ void geometryChanged();
+
+private:
+ void resetPoints();
+ void updateResults();
+
+private:
+ QQuickPdfDocument *m_document = nullptr;
+ QPointF m_fromPoint;
+ QPointF m_toPoint;
+ QString m_text;
+ QVector<QPolygonF> m_geometry;
+ int m_page = 0;
+ bool m_hold = false;
+
+ Q_DISABLE_COPY(QQuickPdfSelection)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickPdfSelection)
+\
+#endif // QQUICKPDFSELECTION_P_H
diff --git a/src/pdf/quick/quick.pro b/src/pdf/quick/quick.pro
new file mode 100644
index 000000000..b62b80346
--- /dev/null
+++ b/src/pdf/quick/quick.pro
@@ -0,0 +1,34 @@
+CXX_MODULE = qml
+TARGET = pdfplugin
+TARGETPATH = QtQuick/Pdf
+IMPORT_VERSION = 1.0
+
+#QMAKE_DOCS = $$PWD/doc/qtquickpdf.qdocconf
+
+PDF_QML_FILES = \
+ qml/PdfMultiPageView.qml \
+ qml/PdfPageView.qml \
+ qml/PdfScrollablePageView.qml \
+
+QML_FILES += $$PDF_QML_FILES qmldir
+
+RESOURCES += resources.qrc
+
+SOURCES += \
+ plugin.cpp \
+ qquickpdfdocument.cpp \
+ qquickpdflinkmodel.cpp \
+ qquickpdfnavigationstack.cpp \
+ qquickpdfsearchmodel.cpp \
+ qquickpdfselection.cpp \
+
+HEADERS += \
+ qquickpdfdocument_p.h \
+ qquickpdflinkmodel_p.h \
+ qquickpdfnavigationstack_p.h \
+ qquickpdfsearchmodel_p.h \
+ qquickpdfselection_p.h \
+
+QT += pdf quick-private gui gui-private core core-private qml qml-private
+
+load(qml_plugin)
diff --git a/src/pdf/quick/resources.qrc b/src/pdf/quick/resources.qrc
new file mode 100644
index 000000000..8270a2028
--- /dev/null
+++ b/src/pdf/quick/resources.qrc
@@ -0,0 +1,10 @@
+<RCC>
+ <qresource prefix="/qt-project.org/qtpdf">
+ <file>qml/+material/PdfStyle.qml</file>
+ <file>qml/+universal/PdfStyle.qml</file>
+ <file>qml/PdfStyle.qml</file>
+ <file>qml/PdfMultiPageView.qml</file>
+ <file>qml/PdfPageView.qml</file>
+ <file>qml/PdfScrollablePageView.qml</file>
+ </qresource>
+</RCC>
diff --git a/src/pdfwidgets/configure.json b/src/pdfwidgets/configure.json
new file mode 100644
index 000000000..b33f08555
--- /dev/null
+++ b/src/pdfwidgets/configure.json
@@ -0,0 +1,28 @@
+{
+ "module": "pdfwidgets",
+ "condition": "module.pdf && features.pdf-widgets",
+ "depends": [
+ "pdf-private"
+ ],
+ "commandline": {
+ "options": {
+ "pdf-widgets": "boolean"
+ }
+ },
+ "features": {
+ "pdf-widgets": {
+ "label": "Support Qt PDF Widgets",
+ "purpose": "Provides Qt PDF Widgets support.",
+ "condition": "module.widgets",
+ "output": [ "privateFeature" ]
+ }
+ },
+ "summary": [
+ {
+ "section": "Qt PDF Widgets",
+ "entries": [
+ "pdf-widgets"
+ ]
+ }
+ ]
+}
diff --git a/src/pdfwidgets/pdfwidgets.pro b/src/pdfwidgets/pdfwidgets.pro
new file mode 100644
index 000000000..cf221be03
--- /dev/null
+++ b/src/pdfwidgets/pdfwidgets.pro
@@ -0,0 +1,12 @@
+TARGET = QtPdfWidgets
+QT = core gui widgets widgets-private pdf
+
+SOURCES += \
+ qpdfview.cpp
+
+HEADERS += \
+ qpdfview.h \
+ qpdfview_p.h \
+ qtpdfwidgetsglobal.h
+
+load(qt_module)
diff --git a/src/pdfwidgets/qpdfview.cpp b/src/pdfwidgets/qpdfview.cpp
new file mode 100644
index 000000000..35e368633
--- /dev/null
+++ b/src/pdfwidgets/qpdfview.cpp
@@ -0,0 +1,493 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfview.h"
+#include "qpdfview_p.h"
+
+#include "qpdfpagerenderer.h"
+
+#include <QGuiApplication>
+#include <QPdfDocument>
+#include <QPdfPageNavigation>
+#include <QScreen>
+#include <QScrollBar>
+#include <QScroller>
+
+QT_BEGIN_NAMESPACE
+
+QPdfViewPrivate::QPdfViewPrivate()
+ : QAbstractScrollAreaPrivate()
+ , m_document(nullptr)
+ , m_pageNavigation(nullptr)
+ , m_pageRenderer(nullptr)
+ , m_pageMode(QPdfView::SinglePage)
+ , m_zoomMode(QPdfView::CustomZoom)
+ , m_zoomFactor(1.0)
+ , m_pageSpacing(3)
+ , m_documentMargins(6, 6, 6, 6)
+ , m_blockPageScrolling(false)
+ , m_pageCacheLimit(20)
+ , m_screenResolution(QGuiApplication::primaryScreen()->logicalDotsPerInch() / 72.0)
+{
+}
+
+void QPdfViewPrivate::init()
+{
+ Q_Q(QPdfView);
+
+ m_pageNavigation = new QPdfPageNavigation(q);
+ m_pageRenderer = new QPdfPageRenderer(q);
+ m_pageRenderer->setRenderMode(QPdfPageRenderer::RenderMode::MultiThreaded);
+}
+
+void QPdfViewPrivate::documentStatusChanged()
+{
+ updateDocumentLayout();
+ invalidatePageCache();
+}
+
+void QPdfViewPrivate::currentPageChanged(int currentPage)
+{
+ Q_Q(QPdfView);
+
+ if (m_blockPageScrolling)
+ return;
+
+ q->verticalScrollBar()->setValue(yPositionForPage(currentPage));
+
+ if (m_pageMode == QPdfView::SinglePage)
+ invalidateDocumentLayout();
+}
+
+void QPdfViewPrivate::calculateViewport()
+{
+ Q_Q(QPdfView);
+
+ const int x = q->horizontalScrollBar()->value();
+ const int y = q->verticalScrollBar()->value();
+ const int width = q->viewport()->width();
+ const int height = q->viewport()->height();
+
+ setViewport(QRect(x, y, width, height));
+}
+
+void QPdfViewPrivate::setViewport(QRect viewport)
+{
+ if (m_viewport == viewport)
+ return;
+
+ const QSize oldSize = m_viewport.size();
+
+ m_viewport = viewport;
+
+ if (oldSize != m_viewport.size()) {
+ updateDocumentLayout();
+
+ if (m_zoomMode != QPdfView::CustomZoom) {
+ invalidatePageCache();
+ }
+ }
+
+ if (m_pageMode == QPdfView::MultiPage) {
+ // An imaginary, 2px height line at the upper half of the viewport, which is used to
+ // determine which page is currently located there -> we propagate that as 'current' page
+ // to the QPdfPageNavigation object
+ 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();
+ if (pageGeometry.intersects(currentPageLine)) {
+ currentPage = it.key();
+ break;
+ }
+ }
+
+ if (currentPage != m_pageNavigation->currentPage()) {
+ m_blockPageScrolling = true;
+ m_pageNavigation->setCurrentPage(currentPage);
+ m_blockPageScrolling = false;
+ }
+ }
+}
+
+void QPdfViewPrivate::updateScrollBars()
+{
+ Q_Q(QPdfView);
+
+ const QSize p = q->viewport()->size();
+ const QSize v = m_documentLayout.documentSize;
+
+ q->horizontalScrollBar()->setRange(0, v.width() - p.width());
+ q->horizontalScrollBar()->setPageStep(p.width());
+ q->verticalScrollBar()->setRange(0, v.height() - p.height());
+ q->verticalScrollBar()->setPageStep(p.height());
+}
+
+void QPdfViewPrivate::pageRendered(int pageNumber, QSize imageSize, const QImage &image, quint64 requestId)
+{
+ Q_Q(QPdfView);
+
+ Q_UNUSED(imageSize)
+ Q_UNUSED(requestId)
+
+ if (!m_cachedPagesLRU.contains(pageNumber)) {
+ if (m_cachedPagesLRU.length() > m_pageCacheLimit)
+ m_pageCache.remove(m_cachedPagesLRU.takeFirst());
+
+ m_cachedPagesLRU.append(pageNumber);
+ }
+
+ m_pageCache.insert(pageNumber, image);
+
+ q->viewport()->update();
+}
+
+void QPdfViewPrivate::invalidateDocumentLayout()
+{
+ updateDocumentLayout();
+ invalidatePageCache();
+}
+
+void QPdfViewPrivate::invalidatePageCache()
+{
+ Q_Q(QPdfView);
+
+ m_pageCache.clear();
+ q->viewport()->update();
+}
+
+QPdfViewPrivate::DocumentLayout QPdfViewPrivate::calculateDocumentLayout() const
+{
+ // The DocumentLayout describes a virtual layout where all pages are positioned inside
+ // - For SinglePage mode, this is just an area as large as the current page surrounded
+ // by the m_documentMargins.
+ // - For MultiPage mode, this is the area that is covered by all pages which are placed
+ // below each other, with m_pageSpacing inbetween and surrounded by m_documentMargins
+
+ DocumentLayout documentLayout;
+
+ if (!m_document || m_document->status() != QPdfDocument::Ready)
+ return documentLayout;
+
+ QHash<int, QRect> pageGeometries;
+
+ const int pageCount = m_document->pageCount();
+
+ int totalWidth = 0;
+
+ const int startPage = (m_pageMode == QPdfView::SinglePage ? m_pageNavigation->currentPage() : 0);
+ const int endPage = (m_pageMode == QPdfView::SinglePage ? m_pageNavigation->currentPage() + 1 : pageCount);
+
+ // calculate page sizes
+ for (int page = startPage; page < endPage; ++page) {
+ QSize pageSize;
+ if (m_zoomMode == QPdfView::CustomZoom) {
+ pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution * m_zoomFactor).toSize();
+ } else if (m_zoomMode == QPdfView::FitToWidth) {
+ pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution).toSize();
+ const qreal factor = (qreal(m_viewport.width() - m_documentMargins.left() - m_documentMargins.right()) / qreal(pageSize.width()));
+ pageSize *= factor;
+ } else if (m_zoomMode == QPdfView::FitInView) {
+ const QSize viewportSize(m_viewport.size() + QSize(-m_documentMargins.left() - m_documentMargins.right(), -m_pageSpacing));
+
+ pageSize = QSizeF(m_document->pageSize(page) * m_screenResolution).toSize();
+ pageSize = pageSize.scaled(viewportSize, Qt::KeepAspectRatio);
+ }
+
+ totalWidth = qMax(totalWidth, pageSize.width());
+
+ pageGeometries[page] = QRect(QPoint(0, 0), pageSize);
+ }
+
+ totalWidth += m_documentMargins.left() + m_documentMargins.right();
+
+ int pageY = m_documentMargins.top();
+
+ // calculate page positions
+ for (int page = startPage; page < endPage; ++page) {
+ const QSize pageSize = pageGeometries[page].size();
+
+ // center horizontal inside the viewport
+ const int pageX = (qMax(totalWidth, m_viewport.width()) - pageSize.width()) / 2;
+
+ pageGeometries[page].moveTopLeft(QPoint(pageX, pageY));
+
+ pageY += pageSize.height() + m_pageSpacing;
+ }
+
+ pageY += m_documentMargins.bottom();
+
+ documentLayout.pageGeometries = pageGeometries;
+
+ // calculate overall document size
+ documentLayout.documentSize = QSize(totalWidth, pageY);
+
+ return documentLayout;
+}
+
+qreal QPdfViewPrivate::yPositionForPage(int pageNumber) const
+{
+ const auto it = m_documentLayout.pageGeometries.constFind(pageNumber);
+ if (it == m_documentLayout.pageGeometries.cend())
+ return 0.0;
+
+ return (*it).y();
+}
+
+void QPdfViewPrivate::updateDocumentLayout()
+{
+ m_documentLayout = calculateDocumentLayout();
+
+ updateScrollBars();
+}
+
+
+QPdfView::QPdfView(QWidget *parent)
+ : QAbstractScrollArea(*new QPdfViewPrivate(), parent)
+{
+ Q_D(QPdfView);
+
+ d->init();
+
+ connect(d->m_pageNavigation, &QPdfPageNavigation::currentPageChanged, this, [d](int page){ d->currentPageChanged(page); });
+
+ connect(d->m_pageRenderer, &QPdfPageRenderer::pageRendered,
+ this, [d](int pageNumber, QSize imageSize, const QImage &image, QPdfDocumentRenderOptions, quint64 requestId){ d->pageRendered(pageNumber, imageSize, image, requestId); });
+
+ verticalScrollBar()->setSingleStep(20);
+ horizontalScrollBar()->setSingleStep(20);
+
+ QScroller::grabGesture(this);
+
+ d->calculateViewport();
+}
+
+/*!
+ \internal
+*/
+QPdfView::QPdfView(QPdfViewPrivate &dd, QWidget *parent)
+ : QAbstractScrollArea(dd, parent)
+{
+}
+
+QPdfView::~QPdfView()
+{
+}
+
+void QPdfView::setDocument(QPdfDocument *document)
+{
+ Q_D(QPdfView);
+
+ if (d->m_document == document)
+ return;
+
+ if (d->m_document)
+ disconnect(d->m_documentStatusChangedConnection);
+
+ d->m_document = document;
+ emit documentChanged(d->m_document);
+
+ if (d->m_document)
+ d->m_documentStatusChangedConnection = connect(d->m_document.data(), &QPdfDocument::statusChanged, this, [d](){ d->documentStatusChanged(); });
+
+ d->m_pageNavigation->setDocument(d->m_document);
+ d->m_pageRenderer->setDocument(d->m_document);
+
+ d->documentStatusChanged();
+}
+
+QPdfDocument *QPdfView::document() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_document;
+}
+
+QPdfPageNavigation *QPdfView::pageNavigation() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_pageNavigation;
+}
+
+QPdfView::PageMode QPdfView::pageMode() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_pageMode;
+}
+
+void QPdfView::setPageMode(PageMode mode)
+{
+ Q_D(QPdfView);
+
+ if (d->m_pageMode == mode)
+ return;
+
+ d->m_pageMode = mode;
+ d->invalidateDocumentLayout();
+
+ emit pageModeChanged(d->m_pageMode);
+}
+
+QPdfView::ZoomMode QPdfView::zoomMode() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_zoomMode;
+}
+
+void QPdfView::setZoomMode(ZoomMode mode)
+{
+ Q_D(QPdfView);
+
+ if (d->m_zoomMode == mode)
+ return;
+
+ d->m_zoomMode = mode;
+ d->invalidateDocumentLayout();
+
+ emit zoomModeChanged(d->m_zoomMode);
+}
+
+qreal QPdfView::zoomFactor() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_zoomFactor;
+}
+
+void QPdfView::setZoomFactor(qreal factor)
+{
+ Q_D(QPdfView);
+
+ if (d->m_zoomFactor == factor)
+ return;
+
+ d->m_zoomFactor = factor;
+ d->invalidateDocumentLayout();
+
+ emit zoomFactorChanged(d->m_zoomFactor);
+}
+
+int QPdfView::pageSpacing() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_pageSpacing;
+}
+
+void QPdfView::setPageSpacing(int spacing)
+{
+ Q_D(QPdfView);
+
+ if (d->m_pageSpacing == spacing)
+ return;
+
+ d->m_pageSpacing = spacing;
+ d->invalidateDocumentLayout();
+
+ emit pageSpacingChanged(d->m_pageSpacing);
+}
+
+QMargins QPdfView::documentMargins() const
+{
+ Q_D(const QPdfView);
+
+ return d->m_documentMargins;
+}
+
+void QPdfView::setDocumentMargins(QMargins margins)
+{
+ Q_D(QPdfView);
+
+ if (d->m_documentMargins == margins)
+ return;
+
+ d->m_documentMargins = margins;
+ d->invalidateDocumentLayout();
+
+ emit documentMarginsChanged(d->m_documentMargins);
+}
+
+void QPdfView::paintEvent(QPaintEvent *event)
+{
+ Q_D(QPdfView);
+
+ QPainter painter(viewport());
+ 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();
+ if (pageGeometry.intersects(d->m_viewport)) { // page needs to be painted
+ painter.fillRect(pageGeometry, Qt::white);
+
+ const int page = it.key();
+ const auto pageIt = d->m_pageCache.constFind(page);
+ if (pageIt != d->m_pageCache.cend()) {
+ const QImage &img = pageIt.value();
+ painter.drawImage(pageGeometry.topLeft(), img);
+ } else {
+ d->m_pageRenderer->requestPage(page, pageGeometry.size());
+ }
+ }
+ }
+}
+
+void QPdfView::resizeEvent(QResizeEvent *event)
+{
+ Q_D(QPdfView);
+
+ QAbstractScrollArea::resizeEvent(event);
+
+ d->updateScrollBars();
+ d->calculateViewport();
+}
+
+void QPdfView::scrollContentsBy(int dx, int dy)
+{
+ Q_D(QPdfView);
+
+ QAbstractScrollArea::scrollContentsBy(dx, dy);
+
+ d->calculateViewport();
+}
+
+QT_END_NAMESPACE
+
+#include "moc_qpdfview.cpp"
diff --git a/src/pdfwidgets/qpdfview.h b/src/pdfwidgets/qpdfview.h
new file mode 100644
index 000000000..cee1cb64c
--- /dev/null
+++ b/src/pdfwidgets/qpdfview.h
@@ -0,0 +1,122 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFVIEW_H
+#define QPDFVIEW_H
+
+#include <QtPdfWidgets/qtpdfwidgetsglobal.h>
+#include <QtWidgets/qabstractscrollarea.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfDocument;
+class QPdfPageNavigation;
+class QPdfViewPrivate;
+
+class Q_PDF_WIDGETS_EXPORT QPdfView : public QAbstractScrollArea
+{
+ Q_OBJECT
+
+ Q_PROPERTY(QPdfDocument* document READ document WRITE setDocument NOTIFY documentChanged)
+
+ Q_PROPERTY(PageMode pageMode READ pageMode WRITE setPageMode NOTIFY pageModeChanged)
+ Q_PROPERTY(ZoomMode zoomMode READ zoomMode WRITE setZoomMode NOTIFY zoomModeChanged)
+ Q_PROPERTY(qreal zoomFactor READ zoomFactor WRITE setZoomFactor NOTIFY zoomFactorChanged)
+
+ Q_PROPERTY(int pageSpacing READ pageSpacing WRITE setPageSpacing NOTIFY pageSpacingChanged)
+ Q_PROPERTY(QMargins documentMargins READ documentMargins WRITE setDocumentMargins NOTIFY documentMarginsChanged)
+
+public:
+ enum PageMode
+ {
+ SinglePage,
+ MultiPage
+ };
+ Q_ENUM(PageMode)
+
+ enum ZoomMode
+ {
+ CustomZoom,
+ FitToWidth,
+ FitInView
+ };
+ Q_ENUM(ZoomMode)
+
+ explicit QPdfView(QWidget *parent = nullptr);
+ ~QPdfView();
+
+ void setDocument(QPdfDocument *document);
+ QPdfDocument *document() const;
+
+ QPdfPageNavigation *pageNavigation() const;
+
+ PageMode pageMode() const;
+ ZoomMode zoomMode() const;
+ qreal zoomFactor() const;
+
+ int pageSpacing() const;
+ void setPageSpacing(int spacing);
+
+ QMargins documentMargins() const;
+ void setDocumentMargins(QMargins margins);
+
+public Q_SLOTS:
+ void setPageMode(PageMode mode);
+ void setZoomMode(ZoomMode mode);
+ void setZoomFactor(qreal factor);
+
+Q_SIGNALS:
+ void documentChanged(QPdfDocument *document);
+ void pageModeChanged(PageMode pageMode);
+ void zoomModeChanged(ZoomMode zoomMode);
+ void zoomFactorChanged(qreal zoomFactor);
+ void pageSpacingChanged(int pageSpacing);
+ void documentMarginsChanged(QMargins documentMargins);
+
+protected:
+ explicit QPdfView(QPdfViewPrivate &, QWidget *);
+
+ void paintEvent(QPaintEvent *event) override;
+ void resizeEvent(QResizeEvent *event) override;
+ void scrollContentsBy(int dx, int dy) override;
+
+private:
+ Q_DECLARE_PRIVATE(QPdfView)
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFVIEW_H
diff --git a/src/pdfwidgets/qpdfview_p.h b/src/pdfwidgets/qpdfview_p.h
new file mode 100644
index 000000000..9fd54b4b6
--- /dev/null
+++ b/src/pdfwidgets/qpdfview_p.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFVIEW_P_H
+#define QPDFVIEW_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 "qpdfview.h"
+
+#include <QPointer>
+#include <QtWidgets/private/qabstractscrollarea_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfPageRenderer;
+
+class QPdfViewPrivate : public QAbstractScrollAreaPrivate
+{
+ Q_DECLARE_PUBLIC(QPdfView)
+
+public:
+ QPdfViewPrivate();
+ void init();
+
+ void documentStatusChanged();
+ void currentPageChanged(int currentPage);
+ void calculateViewport();
+ void setViewport(QRect viewport);
+ void updateScrollBars();
+
+ void pageRendered(int pageNumber, QSize imageSize, const QImage &image, quint64 requestId);
+ void invalidateDocumentLayout();
+ void invalidatePageCache();
+
+ qreal yPositionForPage(int page) const;
+
+ struct DocumentLayout
+ {
+ QSize documentSize;
+ QHash<int, QRect> pageGeometries;
+ };
+
+ DocumentLayout calculateDocumentLayout() const;
+ void updateDocumentLayout();
+
+ QPointer<QPdfDocument> m_document;
+ QPdfPageNavigation* m_pageNavigation;
+ QPdfPageRenderer *m_pageRenderer;
+
+ QPdfView::PageMode m_pageMode;
+ QPdfView::ZoomMode m_zoomMode;
+ qreal m_zoomFactor;
+
+ int m_pageSpacing;
+ QMargins m_documentMargins;
+
+ bool m_blockPageScrolling;
+
+ QMetaObject::Connection m_documentStatusChangedConnection;
+
+ QRect m_viewport;
+
+ QHash<int, QImage> m_pageCache;
+ QVector<int> m_cachedPagesLRU;
+ int m_pageCacheLimit;
+
+ DocumentLayout m_documentLayout;
+
+ qreal m_screenResolution; // pixels per point
+};
+
+Q_DECLARE_TYPEINFO(QPdfViewPrivate::DocumentLayout, Q_MOVABLE_TYPE);
+
+QT_END_NAMESPACE
+
+#endif // QPDFVIEW_P_H
diff --git a/src/pdfwidgets/qtpdfwidgetsglobal.h b/src/pdfwidgets/qtpdfwidgetsglobal.h
new file mode 100644
index 000000000..6c73a34f6
--- /dev/null
+++ b/src/pdfwidgets/qtpdfwidgetsglobal.h
@@ -0,0 +1,59 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTPDFWIDGETSGLOBAL_H
+#define QTPDFWIDGETSGLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef Q_PDF_WIDGETS_EXPORT
+# ifndef QT_STATIC
+# if defined(QT_BUILD_PDFWIDGETS_LIB)
+# define Q_PDF_WIDGETS_EXPORT Q_DECL_EXPORT
+# else
+# define Q_PDF_WIDGETS_EXPORT Q_DECL_IMPORT
+# endif
+# else
+# define Q_PDF_WIDGETS_EXPORT
+# endif
+#endif
+
+QT_END_NAMESPACE
+
+#endif // QTPDFWIDGETSGLOBAL_H
+
diff --git a/src/plugins/imageformats/imageformats.pro b/src/plugins/imageformats/imageformats.pro
new file mode 100644
index 000000000..c3b9cb3a4
--- /dev/null
+++ b/src/plugins/imageformats/imageformats.pro
@@ -0,0 +1,2 @@
+TEMPLATE = subdirs
+SUBDIRS += pdf
diff --git a/src/plugins/imageformats/pdf/main.cpp b/src/plugins/imageformats/pdf/main.cpp
new file mode 100644
index 000000000..b4d59353c
--- /dev/null
+++ b/src/plugins/imageformats/pdf/main.cpp
@@ -0,0 +1,74 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfiohandler_p.h"
+
+QT_BEGIN_NAMESPACE
+
+class QPdfPlugin : public QImageIOPlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID QImageIOHandlerFactoryInterface_iid FILE "pdf.json")
+
+public:
+ Capabilities capabilities(QIODevice *device, const QByteArray &format) const override;
+ QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override;
+};
+
+QImageIOPlugin::Capabilities QPdfPlugin::capabilities(QIODevice *device, const QByteArray &format) const
+{
+ if (format == "pdf")
+ return Capabilities(CanRead);
+ if (!format.isEmpty())
+ return {};
+
+ Capabilities cap;
+ if (device->isReadable() && QPdfIOHandler::canRead(device))
+ cap |= CanRead;
+ return cap;
+}
+
+QImageIOHandler *QPdfPlugin::create(QIODevice *device, const QByteArray &format) const
+{
+ QPdfIOHandler *hand = new QPdfIOHandler();
+ hand->setDevice(device);
+ hand->setFormat(format);
+ return hand;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src/plugins/imageformats/pdf/pdf.json b/src/plugins/imageformats/pdf/pdf.json
new file mode 100644
index 000000000..1f5268ca1
--- /dev/null
+++ b/src/plugins/imageformats/pdf/pdf.json
@@ -0,0 +1,4 @@
+{
+ "Keys": [ "pdf" ],
+ "MimeTypes": [ "application/pdf" ]
+}
diff --git a/src/plugins/imageformats/pdf/pdf.pro b/src/plugins/imageformats/pdf/pdf.pro
new file mode 100644
index 000000000..b820ae7d5
--- /dev/null
+++ b/src/plugins/imageformats/pdf/pdf.pro
@@ -0,0 +1,11 @@
+TARGET = qpdf
+
+PLUGIN_TYPE = imageformats
+PLUGIN_EXTENDS = pdf
+PLUGIN_CLASS_NAME = QPdfPlugin
+load(qt_plugin)
+
+HEADERS += qpdfiohandler_p.h
+SOURCES += main.cpp \
+ qpdfiohandler.cpp
+QT += pdf
diff --git a/src/plugins/imageformats/pdf/qpdfiohandler.cpp b/src/plugins/imageformats/pdf/qpdfiohandler.cpp
new file mode 100644
index 000000000..98e4f4663
--- /dev/null
+++ b/src/plugins/imageformats/pdf/qpdfiohandler.cpp
@@ -0,0 +1,239 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpdfiohandler_p.h"
+#include <QLoggingCategory>
+#include <QPainter>
+
+QT_BEGIN_NAMESPACE
+
+Q_LOGGING_CATEGORY(qLcPdf, "qt.imageformat.pdf")
+
+QPdfIOHandler::QPdfIOHandler()
+{
+}
+
+bool QPdfIOHandler::canRead() const
+{
+ if (!device())
+ return false;
+ if (m_loaded)
+ return true;
+ if (QPdfIOHandler::canRead(device())) {
+ setFormat("pdf");
+ return true;
+ }
+ return false;
+}
+
+bool QPdfIOHandler::canRead(QIODevice *device)
+{
+ char buf[6];
+ device->peek(buf, 6);
+ return (!qstrncmp(buf, "%PDF-", 5) || Q_UNLIKELY(!qstrncmp(buf, "\012%PDF-", 6)));
+}
+
+int QPdfIOHandler::currentImageNumber() const
+{
+ return m_page;
+}
+
+QRect QPdfIOHandler::currentImageRect() const
+{
+ return QRect(QPoint(0, 0), m_doc.pageSize(m_page).toSize());
+}
+
+int QPdfIOHandler::imageCount() const
+{
+ int ret = 0;
+ if (const_cast<QPdfIOHandler *>(this)->load(device()))
+ ret = m_doc.pageCount();
+ qCDebug(qLcPdf) << "imageCount" << ret;
+ return ret;
+}
+
+bool QPdfIOHandler::read(QImage *image)
+{
+ if (load(device())) {
+ if (m_page >= m_doc.pageCount())
+ return false;
+ if (m_page < 0)
+ m_page = 0;
+ const bool xform = (m_clipRect.isValid() || m_scaledSize.isValid() || m_scaledClipRect.isValid());
+ QSize pageSize = m_doc.pageSize(m_page).toSize();
+ QSize finalSize = pageSize;
+ QRectF bounds;
+ if (xform && !finalSize.isEmpty()) {
+ bounds = QRectF(QPointF(0,0), QSizeF(finalSize));
+ QPoint tr1, tr2;
+ QSizeF sc(1, 1);
+ if (m_clipRect.isValid()) {
+ tr1 = -m_clipRect.topLeft();
+ finalSize = m_clipRect.size();
+ }
+ if (m_scaledSize.isValid()) {
+ sc = QSizeF(qreal(m_scaledSize.width()) / finalSize.width(),
+ qreal(m_scaledSize.height()) / finalSize.height());
+ finalSize = m_scaledSize;
+ pageSize = m_scaledSize;
+ }
+ if (m_scaledClipRect.isValid()) {
+ tr2 = -m_scaledClipRect.topLeft();
+ finalSize = m_scaledClipRect.size();
+ }
+ QTransform t;
+ t.translate(tr2.x(), tr2.y());
+ t.scale(sc.width(), sc.height());
+ t.translate(tr1.x(), tr1.y());
+ bounds = t.mapRect(bounds);
+ }
+ qCDebug(qLcPdf) << Q_FUNC_INFO << m_page << finalSize;
+ if (image->size() != finalSize || !image->reinterpretAsFormat(QImage::Format_ARGB32_Premultiplied)) {
+ *image = QImage(finalSize, QImage::Format_ARGB32_Premultiplied);
+ if (!finalSize.isEmpty() && image->isNull()) {
+ // avoid QTBUG-68229
+ qWarning("QPdfIOHandler: QImage allocation failed (size %i x %i)", finalSize.width(), finalSize.height());
+ return false;
+ }
+ }
+ if (!finalSize.isEmpty()) {
+ QPdfDocumentRenderOptions options;
+ if (m_scaledClipRect.isValid())
+ options.setScaledClipRect(m_scaledClipRect);
+ 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();
+ }
+ return true;
+ }
+
+ return false;
+}
+
+QVariant QPdfIOHandler::option(ImageOption option) const
+{
+ switch (option) {
+ case ImageFormat:
+ return QImage::Format_ARGB32_Premultiplied;
+ case Size:
+ const_cast<QPdfIOHandler *>(this)->load(device());
+ return m_doc.pageSize(qMax(0, m_page));
+ case ClipRect:
+ return m_clipRect;
+ case ScaledSize:
+ return m_scaledSize;
+ case ScaledClipRect:
+ return m_scaledClipRect;
+ case BackgroundColor:
+ return m_backColor;
+ case Name:
+ return m_doc.metaData(QPdfDocument::Title);
+ default:
+ break;
+ }
+ return QVariant();
+}
+
+void QPdfIOHandler::setOption(ImageOption option, const QVariant & value)
+{
+ switch (option) {
+ case ClipRect:
+ m_clipRect = value.toRect();
+ break;
+ case ScaledSize:
+ m_scaledSize = value.toSize();
+ break;
+ case ScaledClipRect:
+ m_scaledClipRect = value.toRect();
+ break;
+ case BackgroundColor:
+ m_backColor = value.value<QColor>();
+ break;
+ default:
+ break;
+ }
+}
+
+bool QPdfIOHandler::supportsOption(ImageOption option) const
+{
+ switch (option)
+ {
+ case ImageFormat:
+ case Size:
+ case ClipRect:
+ case ScaledSize:
+ case ScaledClipRect:
+ case BackgroundColor:
+ case Name:
+ return true;
+ default:
+ break;
+ }
+ return false;
+}
+
+bool QPdfIOHandler::jumpToImage(int frame)
+{
+ qCDebug(qLcPdf) << Q_FUNC_INFO << frame;
+ if (frame < 0 || frame >= m_doc.pageCount())
+ return false;
+ m_page = frame;
+ return true;
+}
+
+bool QPdfIOHandler::jumpToNextImage()
+{
+ return jumpToImage(m_page + 1);
+}
+
+bool QPdfIOHandler::load(QIODevice *device)
+{
+ if (m_loaded)
+ return true;
+ if (format().isEmpty())
+ if (!canRead())
+ return false;
+
+ m_doc.load(device);
+ m_loaded = (m_doc.error() == QPdfDocument::DocumentError::NoError);
+
+ return m_loaded;
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/imageformats/pdf/qpdfiohandler_p.h b/src/plugins/imageformats/pdf/qpdfiohandler_p.h
new file mode 100644
index 000000000..99a91154c
--- /dev/null
+++ b/src/plugins/imageformats/pdf/qpdfiohandler_p.h
@@ -0,0 +1,88 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPDFIOHANDLER_H
+#define QPDFIOHANDLER_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 <QtGui/qimageiohandler.h>
+#include <QtPdf/QPdfDocument>
+
+QT_BEGIN_NAMESPACE
+
+class QPdfIOHandler : public QImageIOHandler
+{
+public:
+ QPdfIOHandler();
+ bool canRead() const override;
+ static bool canRead(QIODevice *device);
+ int currentImageNumber() const override;
+ QRect currentImageRect() const override;
+ int imageCount() const override;
+ bool read(QImage *image) override;
+ QVariant option(ImageOption option) const override;
+ void setOption(ImageOption option, const QVariant & value) override;
+ bool supportsOption(ImageOption option) const override;
+ bool jumpToImage(int frame) override;
+ bool jumpToNextImage() override;
+
+private:
+ bool load(QIODevice *device);
+
+private:
+ QPdfDocument m_doc;
+ int m_page = -1;
+
+ QRect m_clipRect;
+ QSize m_scaledSize;
+ QRect m_scaledClipRect;
+ QColor m_backColor = Qt::transparent;
+ bool m_loaded = false;
+};
+
+QT_END_NAMESPACE
+
+#endif // QPDFIOHANDLER_H
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 6698a9736..50181aa19 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -1,2 +1,3 @@
TEMPLATE = subdirs
-qtHaveModule(designer): SUBDIRS += qwebengineview
+qtHaveModule(webenginewidgets): qtHaveModule(designer): SUBDIRS += qwebengineview
+qtHaveModule(pdf): qtConfig(imageformatplugin): SUBDIRS += imageformats
diff --git a/src/process/Entitlements_mac.plist b/src/process/QtWebEngineProcess.entitlements
index f2fbabddb..f2fbabddb 100644
--- a/src/process/Entitlements_mac.plist
+++ b/src/process/QtWebEngineProcess.entitlements
diff --git a/src/process/process.pro b/src/process/process.pro
index e861af182..66fdf9797 100644
--- a/src/process/process.pro
+++ b/src/process/process.pro
@@ -39,13 +39,23 @@ win32 {
msvc: QMAKE_LFLAGS += /MANIFESTINPUT:$$PWD/process.exe.manifest
}
-load(qt_app)
+TEMPLATE = app
+
+load(qt_build_paths)
+
+!build_pass:qtConfig(debug_and_release): CONFIG += release
+CONFIG += relative_qt_rpath
qtConfig(build_all): CONFIG += build_all
qtConfig(framework) {
# Deploy the QtWebEngineProcess app bundle into the QtWebEngineCore framework.
DESTDIR = $$MODULE_BASE_OUTDIR/lib/QtWebEngineCore.framework/Versions/5/Helpers
+
+ # Deploy the entitlements file so macdeployqt can use it.
+ entitlements.files = QtWebEngineProcess.entitlements
+ entitlements.path = Contents/Resources/
+ QMAKE_BUNDLE_DATA += entitlements
} else {
CONFIG -= app_bundle
win32: DESTDIR = $$MODULE_BASE_OUTDIR/bin
@@ -58,3 +68,8 @@ qtConfig(framework) {
} else {
target.path = $$[QT_INSTALL_LIBEXECS]
}
+
+load(qt_targets)
+load(qt_common)
+
+INSTALLS += target
diff --git a/src/src.pro b/src/src.pro
index de88878a6..063c148b5 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -4,9 +4,11 @@ include($$QTWEBENGINE_OUT_ROOT/src/buildtools/qtbuildtools-config.pri)
include($$QTWEBENGINE_OUT_ROOT/src/core/qtwebenginecore-config.pri)
include($$QTWEBENGINE_OUT_ROOT/src/webengine/qtwebengine-config.pri)
include($$QTWEBENGINE_OUT_ROOT/src/webenginewidgets/qtwebenginewidgets-config.pri)
+include($$QTWEBENGINE_OUT_ROOT/src/pdf/qtpdf-config.pri)
+include($$QTWEBENGINE_OUT_ROOT/src/pdfwidgets/qtpdfwidgets-config.pri)
QT_FOR_CONFIG += buildtools-private webenginecore webenginecore-private webengine-private \
- webenginewidgets-private
+ webenginewidgets-private pdf-private pdfwidgets-private
TEMPLATE = subdirs
@@ -38,7 +40,20 @@ qtConfig(build-qtwebengine-core):qtConfig(webengine-core-support) {
}
}
-!qtConfig(webengine-core-support): qtConfig(build-qtwebengine-core) {
+qtConfig(build-qtpdf):qtConfig(webengine-qtpdf-support) {
+ pdf.depends = buildtools
+ qtConfig(build-qtwebengine-core):qtConfig(webengine-core-support): pdf.depends += core
+ SUBDIRS += pdf
+ !contains(SUBDIRS, buildtools): SUBDIRS += buildtools
+ !contains(SUBDIRS, plugins): SUBDIRS += plugins
+ plugins.depends += pdf
+ qtConfig(pdf-widgets) {
+ pdfwidgets.depends = pdf
+ SUBDIRS += pdfwidgets
+ }
+}
+
+!qtConfig(webengine-core-support):if(qtConfig(build-qtwebengine-core)|qtConfig(build-qtpdf)) {
!qtwebengine_makeCheckError():!isEmpty(skipBuildReason):!build_pass {
errorbuild.commands = @echo Modules will not be built. $${skipBuildReason}
errorbuild.CONFIG = phony
diff --git a/src/tools/qwebengine_convert_dict/main.cpp b/src/tools/qwebengine_convert_dict/main.cpp
index 1694dbcef..0ebba96b1 100644
--- a/src/tools/qwebengine_convert_dict/main.cpp
+++ b/src/tools/qwebengine_convert_dict/main.cpp
@@ -84,7 +84,7 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words,
hunspell::BDictReader reader;
if (!reader.Init(reinterpret_cast<const unsigned char*>(serialized.data()),
serialized.size())) {
- out << "BDict is invalid" << endl;
+ out << "BDict is invalid" << Qt::endl;
return false;
}
hunspell::WordIterator iter = reader.GetAllWordIterator();
@@ -96,7 +96,7 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words,
for (size_t i = 0; i < org_words.size(); i++) {
int affix_matches = iter.Advance(buf, buf_size, affix_ids);
if (affix_matches == 0) {
- out << "Found the end before we expected" << endl;
+ out << "Found the end before we expected" << Qt::endl;
return false;
}
@@ -104,7 +104,7 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words,
out << "Word does not match!\n"
<< " Index: " << i << "\n"
<< " Expected: " << QString::fromStdString(org_words[i].first) << "\n"
- << " Actual: " << QString::fromUtf8(buf) << endl;
+ << " Actual: " << QString::fromUtf8(buf) << Qt::endl;
return false;
}
@@ -118,7 +118,7 @@ inline bool VerifyWords(const convert_dict::DicReader::WordList& org_words,
<< " Index: " << i << "\n"
<< " Word: " << QString::fromUtf8(buf) << "\n"
<< " Expected: " << expectedAffixes << "\n"
- << " Actual: " << actualAffixes << endl;
+ << " Actual: " << actualAffixes << Qt::endl;
return false;
}
}
@@ -148,7 +148,7 @@ int main(int argc, char *argv[])
out << "Usage: qwebengine_convert_dict <dic file> <bdic file>\n\nExample:\n"
"qwebengine_convert_dict ./en-US.dic ./en-US.bdic\nwill read en-US.dic, "
"en-US.dic_delta, and en-US.aff from the current directory and generate "
- "en-US.bdic\n" << endl;
+ "en-US.bdic\n" << Qt::endl;
return 1;
}
@@ -184,7 +184,7 @@ int main(int argc, char *argv[])
out << "Couldn't find ICU data directory. Please check that the following path exists: "
<< icuDataDir
<< "\nAlternatively provide the directory path via the QT_WEBENGINE_ICU_DAT_DIR "
- "environment variable.\n" << endl;
+ "environment variable.\n" << Qt::endl;
return 1;
}
@@ -196,21 +196,21 @@ int main(int argc, char *argv[])
base::FilePath file_out_path = toFilePath(argv[2]);
base::FilePath aff_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".aff"));
- out << "Reading " << toQt(aff_path.value()) << endl;
+ out << "Reading " << toQt(aff_path.value()) << Qt::endl;
convert_dict::AffReader aff_reader(aff_path);
if (!aff_reader.Read()) {
- out << "Unable to read the aff file." << endl;
+ out << "Unable to read the aff file." << Qt::endl;
return 1;
}
base::FilePath dic_path = file_in_path.ReplaceExtension(FILE_PATH_LITERAL(".dic"));
- out << "Reading " << toQt(dic_path.value()) << endl;
+ out << "Reading " << toQt(dic_path.value()) << Qt::endl;
// DicReader will also read the .dic_delta file.
convert_dict::DicReader dic_reader(dic_path);
if (!dic_reader.Read(&aff_reader)) {
- out << "Unable to read the dic file." << endl;
+ out << "Unable to read the dic file." << Qt::endl;
return 1;
}
@@ -222,27 +222,27 @@ int main(int argc, char *argv[])
writer.SetOtherCommands(aff_reader.other_commands());
writer.SetWords(dic_reader.words());
- out << "Serializing..." << endl;
+ out << "Serializing..." << Qt::endl;
std::string serialized = writer.GetBDict();
- out << "Verifying..." << endl;
+ out << "Verifying..." << Qt::endl;
if (!VerifyWords(dic_reader.words(), serialized, out)) {
- out << "ERROR converting, the dictionary does not check out OK." << endl;
+ out << "ERROR converting, the dictionary does not check out OK." << Qt::endl;
return 1;
}
- out << "Writing " << toQt(file_out_path.value()) << endl;
+ out << "Writing " << toQt(file_out_path.value()) << Qt::endl;
FILE *out_file = base::OpenFile(file_out_path, "wb");
if (!out_file) {
- out << "ERROR writing file" << endl;
+ out << "ERROR writing file" << Qt::endl;
return 1;
}
size_t written = fwrite(&serialized[0], 1, serialized.size(), out_file);
Q_ASSERT(written == serialized.size());
base::CloseFile(out_file);
- out << "Success. Dictionary converted." << endl;
+ out << "Success. Dictionary converted." << Qt::endl;
return 0;
}
diff --git a/src/webengine/api/qquickwebenginehistory.cpp b/src/webengine/api/qquickwebenginehistory.cpp
index d3c4a0026..e77974a0f 100644
--- a/src/webengine/api/qquickwebenginehistory.cpp
+++ b/src/webengine/api/qquickwebenginehistory.cpp
@@ -327,6 +327,20 @@ QQuickWebEngineHistoryListModel *QQuickWebEngineHistory::forwardItems() const
return d->m_forwardNavigationModel.data();
}
+/*!
+ \qmlmethod void WebEngineHistory::clear()
+ \since QtWebEngine 1.11
+
+ Clears the history.
+*/
+void QQuickWebEngineHistory::clear()
+{
+ Q_D(QQuickWebEngineHistory);
+ d->m_view->adapter->clearNavigationHistory();
+ d->m_view->updateNavigationActions();
+ reset();
+}
+
void QQuickWebEngineHistory::reset()
{
Q_D(QQuickWebEngineHistory);
diff --git a/src/webengine/api/qquickwebenginehistory_p.h b/src/webengine/api/qquickwebenginehistory_p.h
index bf049b2a6..5d4783e96 100644
--- a/src/webengine/api/qquickwebenginehistory_p.h
+++ b/src/webengine/api/qquickwebenginehistory_p.h
@@ -107,6 +107,7 @@ public:
QQuickWebEngineHistoryListModel *items() const;
QQuickWebEngineHistoryListModel *backItems() const;
QQuickWebEngineHistoryListModel *forwardItems() const;
+ Q_REVISION(1) Q_INVOKABLE void clear();
void reset();
diff --git a/src/webengine/api/qquickwebenginetestsupport.cpp b/src/webengine/api/qquickwebenginetestsupport.cpp
index b7b863125..bef87160e 100644
--- a/src/webengine/api/qquickwebenginetestsupport.cpp
+++ b/src/webengine/api/qquickwebenginetestsupport.cpp
@@ -157,7 +157,7 @@ void QQuickWebEngineTestEvent::mouseEvent(QEvent::Type type, QWindow *window, QO
if (sgitem)
pos = sgitem->mapToScene(_pos).toPoint();
- QMouseEvent me(type, pos, window->mapFromGlobal(pos), Qt::LeftButton, Qt::LeftButton, 0);
+ QMouseEvent me(type, pos, window->mapFromGlobal(pos), Qt::LeftButton, Qt::LeftButton, {});
me.setTimestamp(++QTest::lastMouseTimestamp);
QSpontaneKeyEvent::setSpontaneous(&me);
diff --git a/src/webengine/api/qquickwebengineview.cpp b/src/webengine/api/qquickwebengineview.cpp
index dead005b0..bcbf95569 100644
--- a/src/webengine/api/qquickwebengineview.cpp
+++ b/src/webengine/api/qquickwebengineview.cpp
@@ -428,6 +428,12 @@ void QQuickWebEngineViewPrivate::recentlyAudibleChanged(bool recentlyAudible)
Q_EMIT q->recentlyAudibleChanged(recentlyAudible);
}
+void QQuickWebEngineViewPrivate::renderProcessPidChanged(qint64 pid)
+{
+ Q_Q(QQuickWebEngineView);
+ Q_EMIT q->renderProcessPidChanged(pid);
+}
+
QRectF QQuickWebEngineViewPrivate::viewportRect() const
{
Q_Q(const QQuickWebEngineView);
@@ -1429,6 +1435,12 @@ bool QQuickWebEngineView::recentlyAudible() const
return d->adapter->recentlyAudible();
}
+qint64 QQuickWebEngineView::renderProcessPid() const
+{
+ const Q_D(QQuickWebEngineView);
+ return d->adapter->renderProcessPid();
+}
+
void QQuickWebEngineView::printToPdf(const QString& filePath, PrintedPageSizeId pageSizeId, PrintedPageOrientation orientation)
{
#if QT_CONFIG(webengine_printing_and_pdf)
diff --git a/src/webengine/api/qquickwebengineview_p.h b/src/webengine/api/qquickwebengineview_p.h
index 618f9407e..ab84b2600 100644
--- a/src/webengine/api/qquickwebengineview_p.h
+++ b/src/webengine/api/qquickwebengineview_p.h
@@ -142,6 +142,8 @@ class Q_WEBENGINE_PRIVATE_EXPORT QQuickWebEngineView : public QQuickItem {
Q_PROPERTY(LifecycleState lifecycleState READ lifecycleState WRITE setLifecycleState NOTIFY lifecycleStateChanged REVISION 10 FINAL)
Q_PROPERTY(LifecycleState recommendedState READ recommendedState NOTIFY recommendedStateChanged REVISION 10 FINAL)
+ Q_PROPERTY(qint64 renderProcessPid READ renderProcessPid NOTIFY renderProcessPidChanged FINAL REVISION 11)
+
public:
QQuickWebEngineView(QQuickItem *parent = 0);
~QQuickWebEngineView();
@@ -493,6 +495,8 @@ public:
void setAudioMuted(bool muted);
bool recentlyAudible() const;
+ qint64 renderProcessPid() const;
+
#if QT_CONFIG(webengine_testsupport)
QQuickWebEngineTestSupport *testSupport() const;
void setTestSupport(QQuickWebEngineTestSupport *testSupport);
@@ -520,7 +524,7 @@ public Q_SLOTS:
void reload();
Q_REVISION(1) void reloadAndBypassCache();
void stop();
- Q_REVISION(1) void findText(const QString &subString, FindFlags options = 0, const QJSValue &callback = QJSValue());
+ Q_REVISION(1) void findText(const QString &subString, FindFlags options = { }, const QJSValue &callback = QJSValue());
Q_REVISION(1) void fullScreenCancelled();
Q_REVISION(1) void grantFeaturePermission(const QUrl &securityOrigin, Feature, bool granted);
Q_REVISION(2) void setActiveFocusOnPress(bool arg);
@@ -576,6 +580,7 @@ Q_SIGNALS:
Q_REVISION(10) void lifecycleStateChanged(LifecycleState state);
Q_REVISION(10) void recommendedStateChanged(LifecycleState state);
Q_REVISION(10) void findTextFinished(const QWebEngineFindTextResult &result);
+ Q_REVISION(11) void renderProcessPidChanged(qint64 pid);
#if QT_CONFIG(webengine_testsupport)
void testSupportChanged();
diff --git a/src/webengine/api/qquickwebengineview_p_p.h b/src/webengine/api/qquickwebengineview_p_p.h
index 3969ee244..6f9b552ec 100644
--- a/src/webengine/api/qquickwebengineview_p_p.h
+++ b/src/webengine/api/qquickwebengineview_p_p.h
@@ -112,6 +112,7 @@ public:
void didUpdateTargetURL(const QUrl&) override;
void selectionChanged() override;
void recentlyAudibleChanged(bool recentlyAudible) override;
+ void renderProcessPidChanged(qint64 pid) override;
QRectF viewportRect() const override;
QColor backgroundColor() const override;
void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override;
diff --git a/src/webengine/doc/src/qwebengine-licensing.qdoc b/src/webengine/doc/src/qwebengine-licensing.qdoc
index 8795ca44c..f6a0a6c32 100644
--- a/src/webengine/doc/src/qwebengine-licensing.qdoc
+++ b/src/webengine/doc/src/qwebengine-licensing.qdoc
@@ -26,7 +26,6 @@
****************************************************************************/
/*!
-\contentspage qtwebengine-licensing.html
\group qtwebengine-licensing
\title Qt WebEngine Licensing
@@ -43,7 +42,6 @@ Third party licenses included in the sources are:
*/
/*!
-\contentspage qtwebengine-licensing.html
\page qtwebengine-3rdparty-chromium-global.html attribution
\ingroup qtwebengine-licensing
\title Chromium License
diff --git a/src/webengine/doc/src/webengineview_lgpl.qdoc b/src/webengine/doc/src/webengineview_lgpl.qdoc
index 6e349dfb3..0cd8441cf 100644
--- a/src/webengine/doc/src/webengineview_lgpl.qdoc
+++ b/src/webengine/doc/src/webengineview_lgpl.qdoc
@@ -1614,3 +1614,27 @@
\sa findText(), FindTextResult
*/
+
+/*!
+ \qmlproperty qint64 WebEngineView::renderProcessPid
+ \brief Returns the process ID (PID) of the render process assigned to the
+ current page's main frame.
+ \since QtWebEngine 1.11
+ \readonly
+
+ If no render process is available yet, \c 0 is returned.
+
+ \sa renderProcessPidChanged
+*/
+
+/*!
+ \qmlsignal WebEngineView::renderProcessPidChanged(qint64 pid)
+ \since QtWebEngine 1.11
+ \readonly
+
+ If no render process is available yet, \c 0 is returned.
+ This signal is emitted when the PID (process ID) of the page's underlying
+ render process changed.
+
+ \sa renderProcessPid
+*/
diff --git a/src/webengine/plugin/plugin.cpp b/src/webengine/plugin/plugin.cpp
index 3acf7d058..a74373b23 100644
--- a/src/webengine/plugin/plugin.cpp
+++ b/src/webengine/plugin/plugin.cpp
@@ -97,6 +97,7 @@ public:
qmlRegisterType<QQuickWebEngineView, 8>(uri, 1, 8, "WebEngineView");
qmlRegisterType<QQuickWebEngineView, 9>(uri, 1, 9, "WebEngineView");
qmlRegisterType<QQuickWebEngineView, 10>(uri, 1, 10, "WebEngineView");
+ qmlRegisterType<QQuickWebEngineView, 11>(uri, 1, 11, "WebEngineView");
qmlRegisterType<QQuickWebEngineProfile>(uri, 1, 1, "WebEngineProfile");
qmlRegisterType<QQuickWebEngineProfile, 1>(uri, 1, 2, "WebEngineProfile");
qmlRegisterType<QQuickWebEngineProfile, 2>(uri, 1, 3, "WebEngineProfile");
@@ -137,6 +138,7 @@ public:
qmlRegisterSingletonType<QQuickWebEngineSingleton>(uri, 1, 1, "WebEngine", webEngineSingletonProvider);
qmlRegisterUncreatableType<QQuickWebEngineHistory>(uri, 1, 1, "NavigationHistory",
msgUncreatableType("NavigationHistory"));
+ qmlRegisterUncreatableType<QQuickWebEngineHistory, 1>(uri, 1, 11, "NavigationHistory", msgUncreatableType("NavigationHistory"));
qmlRegisterUncreatableType<QQuickWebEngineHistoryListModel>(uri, 1, 1, "NavigationHistoryListModel",
msgUncreatableType("NavigationHistory"));
qmlRegisterUncreatableType<QQuickWebEngineFullScreenRequest>(uri, 1, 1, "FullScreenRequest",
diff --git a/src/webengine/plugin/plugins.qmltypes b/src/webengine/plugin/plugins.qmltypes
index a23d1c3c0..24b073290 100644
--- a/src/webengine/plugin/plugins.qmltypes
+++ b/src/webengine/plugin/plugins.qmltypes
@@ -1348,6 +1348,7 @@ Module {
Property { name: "devToolsView"; revision: 7; type: "QQuickWebEngineView"; isPointer: true }
Property { name: "lifecycleState"; revision: 10; type: "LifecycleState" }
Property { name: "recommendedState"; revision: 10; type: "LifecycleState"; isReadonly: true }
+ Property { name: "renderProcessId"; revision: 11; type: "qint64"; isReadonly: true }
Signal {
name: "loadingChanged"
Parameter { name: "loadRequest"; type: "QQuickWebEngineLoadRequest"; isPointer: true }
@@ -1526,6 +1527,11 @@ Module {
revision: 10
Parameter { name: "result"; type: "QWebEngineFindTextResult" }
}
+ Signal {
+ name: "renderProcessPidChanged"
+ revision: 11
+ Parameter { name: "pid"; type: "qint64" }
+ }
Method {
name: "runJavaScript"
Parameter { type: "string" }
diff --git a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
index d3ebdbf27..1de4d8835 100644
--- a/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
+++ b/src/webengine/render_widget_host_view_qt_delegate_quickwindow.cpp
@@ -48,7 +48,7 @@ RenderWidgetHostViewQtDelegateQuickWindow::RenderWidgetHostViewQtDelegateQuickWi
: m_realDelegate(realDelegate)
, m_virtualParent(nullptr)
{
- setFlags(Qt::Tool | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
+ setFlags(Qt::Tool | Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::WindowDoesNotAcceptFocus);
}
RenderWidgetHostViewQtDelegateQuickWindow::~RenderWidgetHostViewQtDelegateQuickWindow()
diff --git a/src/webenginewidgets/api/qwebenginepage.cpp b/src/webenginewidgets/api/qwebenginepage.cpp
index 850a29a16..ad6196850 100644
--- a/src/webenginewidgets/api/qwebenginepage.cpp
+++ b/src/webenginewidgets/api/qwebenginepage.cpp
@@ -277,6 +277,12 @@ void QWebEnginePagePrivate::recentlyAudibleChanged(bool recentlyAudible)
Q_EMIT q->recentlyAudibleChanged(recentlyAudible);
}
+void QWebEnginePagePrivate::renderProcessPidChanged(qint64 pid)
+{
+ Q_Q(QWebEnginePage);
+ Q_EMIT q->renderProcessPidChanged(pid);
+}
+
QRectF QWebEnginePagePrivate::viewportRect() const
{
return view ? view->rect() : QRectF();
@@ -937,6 +943,13 @@ QWebEnginePage::QWebEnginePage(QObject* parent)
*/
/*!
+ \fn void QWebEnginePage::renderProcessPidChanged(qint64 pid);
+ \since 5.15
+
+ This signal is emitted when the underlying render process PID, \a renderProcessPid, changes.
+*/
+
+/*!
\fn void QWebEnginePage::iconUrlChanged(const QUrl &url)
This signal is emitted when the URL of the icon ("favicon") associated with the
@@ -1149,6 +1162,20 @@ bool QWebEnginePage::recentlyAudible() const
return d->adapter->isInitialized() && d->adapter->recentlyAudible();
}
+/*!
+ \property QWebEnginePage::renderProcessPid
+ \brief The process ID (PID) of the render process assigned to the current
+ page's main frame.
+ \since 5.15
+
+ If no render process is available yet, \c 0 is returned.
+*/
+qint64 QWebEnginePage::renderProcessPid() const
+{
+ Q_D(const QWebEnginePage);
+ return d->adapter->renderProcessPid();
+}
+
void QWebEnginePage::setView(QWidget *newViewBase)
{
QWebEnginePagePrivate::bindPageAndView(this, qobject_cast<QWebEngineView *>(newViewBase));
@@ -2312,7 +2339,7 @@ QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringLis
QString str;
switch (static_cast<FilePickerController::FileChooserMode>(mode)) {
case FilePickerController::OpenMultiple:
- ret = QFileDialog::getOpenFileNames(view(), QString(), QString(), filter.join(";;"), nullptr, QFileDialog::HideNameFilterDetails);
+ ret = QFileDialog::getOpenFileNames(view(), QString(), QString(), filter.join(QStringLiteral(";;")), nullptr, QFileDialog::HideNameFilterDetails);
break;
// Chromium extension, not exposed as part of the public API for now.
case FilePickerController::UploadFolder:
@@ -2326,7 +2353,7 @@ QStringList QWebEnginePage::chooseFiles(FileSelectionMode mode, const QStringLis
ret << str;
break;
case FilePickerController::Open:
- str = QFileDialog::getOpenFileName(view(), QString(), oldFiles.first(), filter.join(";;"), nullptr, QFileDialog::HideNameFilterDetails);
+ str = QFileDialog::getOpenFileName(view(), QString(), oldFiles.first(), filter.join(QStringLiteral(";;")), nullptr, QFileDialog::HideNameFilterDetails);
if (!str.isNull())
ret << str;
break;
diff --git a/src/webenginewidgets/api/qwebenginepage.h b/src/webenginewidgets/api/qwebenginepage.h
index cd012ea70..3cf6a9f8b 100644
--- a/src/webenginewidgets/api/qwebenginepage.h
+++ b/src/webenginewidgets/api/qwebenginepage.h
@@ -92,6 +92,7 @@ class QWEBENGINEWIDGETS_EXPORT QWebEnginePage : public QObject {
Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(LifecycleState lifecycleState READ lifecycleState WRITE setLifecycleState NOTIFY lifecycleStateChanged)
Q_PROPERTY(LifecycleState recommendedState READ recommendedState NOTIFY recommendedStateChanged)
+ Q_PROPERTY(qint64 renderProcessPid READ renderProcessPid NOTIFY renderProcessPidChanged)
public:
enum WebAction {
@@ -305,6 +306,7 @@ public:
bool isAudioMuted() const;
void setAudioMuted(bool muted);
bool recentlyAudible() const;
+ qint64 renderProcessPid() const;
void printToPdf(const QString &filePath, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()));
void printToPdf(const QWebEngineCallback<const QByteArray&> &resultCallback, const QPageLayout &layout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF()));
@@ -361,6 +363,7 @@ Q_SIGNALS:
void contentsSizeChanged(const QSizeF &size);
void audioMutedChanged(bool muted);
void recentlyAudibleChanged(bool recentlyAudible);
+ void renderProcessPidChanged(qint64 pid);
void pdfPrintingFinished(const QString &filePath, bool success);
void printRequested();
diff --git a/src/webenginewidgets/api/qwebenginepage_p.h b/src/webenginewidgets/api/qwebenginepage_p.h
index e78b0f926..7fdc811e2 100644
--- a/src/webenginewidgets/api/qwebenginepage_p.h
+++ b/src/webenginewidgets/api/qwebenginepage_p.h
@@ -103,6 +103,7 @@ public:
void didUpdateTargetURL(const QUrl&) override;
void selectionChanged() override;
void recentlyAudibleChanged(bool recentlyAudible) override;
+ void renderProcessPidChanged(qint64 pid) override;
QRectF viewportRect() const override;
QColor backgroundColor() const override;
void loadStarted(const QUrl &provisionalUrl, bool isErrorPage = false) override;
diff --git a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc
index 0706598ef..7043469a0 100644
--- a/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc
+++ b/src/webenginewidgets/doc/src/qwebenginesettings_lgpl.qdoc
@@ -114,8 +114,7 @@
subresources, such as scripts, and therefore disabling this setting is not a safety
mechanism.
\value XSSAuditingEnabled
- Monitors load requests for cross-site scripting attempts. Suspicious scripts are blocked
- and reported in the inspector's JavaScript console. Enabled by default.
+ Obsolete and has no effect.
\value SpatialNavigationEnabled
Enables the Spatial Navigation feature, which means the ability to navigate between
focusable elements, such as hyperlinks and form controls, on a web page by using the
diff --git a/sync.profile b/sync.profile
index 4cc549106..a1e3c8ded 100644
--- a/sync.profile
+++ b/sync.profile
@@ -2,11 +2,14 @@
"QtWebEngine" => "$basedir/src/webengine",
"QtWebEngineWidgets" => "$basedir/src/webenginewidgets",
"QtWebEngineCore" => "$basedir/src/core",
+ "QtPdf" => "$basedir/src/pdf",
+ "QtPdfWidgets" => "$basedir/src/pdfwidgets",
);
%moduleheaders = ( # restrict the module headers to those found in relative path
"QtWebEngine" => "api",
"QtWebEngineWidgets" => "api",
"QtWebEngineCore" => "api",
+ "QtPdf" => "api"
);
%classnames = (
);
diff --git a/tests/auto/auto.pro b/tests/auto/auto.pro
index 59bcd5aef..9b71e1183 100644
--- a/tests/auto/auto.pro
+++ b/tests/auto/auto.pro
@@ -7,3 +7,8 @@ qtHaveModule(webengine) {
qtHaveModule(webenginewidgets) {
SUBDIRS += core widgets
}
+
+qtHaveModule(pdf) {
+ SUBDIRS += pdf
+}
+
diff --git a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
index a7b44602f..5effb2abf 100644
--- a/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
+++ b/tests/auto/core/qwebengineurlrequestinterceptor/tst_qwebengineurlrequestinterceptor.cpp
@@ -290,18 +290,21 @@ void tst_QWebEngineUrlRequestInterceptor::requestedUrl()
page.setUrl(QUrl("qrc:///resources/__placeholder__"));
QVERIFY(spy.wait());
QTRY_COMPARE(spy.count(), 1);
+ QVERIFY(interceptor.requestInfos.count() >= 1);
QCOMPARE(interceptor.requestInfos.at(0).requestUrl, QUrl("qrc:///resources/content.html"));
QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__"));
QCOMPARE(page.url(), QUrl("qrc:///resources/content.html"));
page.setUrl(QUrl("qrc:/non-existent.html"));
QTRY_COMPARE(spy.count(), 2);
+ QVERIFY(interceptor.requestInfos.count() >= 3);
QCOMPARE(interceptor.requestInfos.at(2).requestUrl, QUrl("qrc:/non-existent.html"));
QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__"));
QCOMPARE(page.url(), QUrl("qrc:///resources/content.html"));
page.setUrl(QUrl("http://abcdef.abcdef"));
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 3, 15000);
+ QVERIFY(interceptor.requestInfos.count() >= 4);
QCOMPARE(interceptor.requestInfos.at(3).requestUrl, QUrl("http://abcdef.abcdef/"));
QCOMPARE(page.requestedUrl(), QUrl("qrc:///resources/__placeholder__"));
QCOMPARE(page.url(), QUrl("qrc:///resources/content.html"));
@@ -359,6 +362,7 @@ void tst_QWebEngineUrlRequestInterceptor::firstPartyUrl()
page.setUrl(QUrl("qrc:///resources/firstparty.html"));
QVERIFY(spy.wait());
+ QVERIFY(interceptor.requestInfos.count() >= 2);
QCOMPARE(interceptor.requestInfos.at(0).requestUrl, QUrl("qrc:///resources/firstparty.html"));
QCOMPARE(interceptor.requestInfos.at(1).requestUrl, QUrl("qrc:///resources/content.html"));
QCOMPARE(interceptor.requestInfos.at(0).firstPartyUrl, QUrl("qrc:///resources/firstparty.html"));
@@ -393,16 +397,19 @@ void tst_QWebEngineUrlRequestInterceptor::firstPartyUrlNestedIframes()
page.setUrl(requestUrl);
QTRY_COMPARE(loadSpy.count(), 1);
+ QVERIFY(interceptor.requestInfos.count() >= 1);
RequestInfo info = interceptor.requestInfos.at(0);
QCOMPARE(info.requestUrl, requestUrl);
QCOMPARE(info.firstPartyUrl, requestUrl);
QCOMPARE(info.resourceType, QWebEngineUrlRequestInfo::ResourceTypeMainFrame);
+ QVERIFY(interceptor.requestInfos.count() >= 2);
info = interceptor.requestInfos.at(1);
QCOMPARE(info.requestUrl, QUrl(adjustedUrl + "iframe2.html"));
QCOMPARE(info.firstPartyUrl, requestUrl);
QCOMPARE(info.resourceType, QWebEngineUrlRequestInfo::ResourceTypeSubFrame);
+ QVERIFY(interceptor.requestInfos.count() >= 3);
info = interceptor.requestInfos.at(2);
QCOMPARE(info.requestUrl, QUrl(adjustedUrl + "iframe3.html"));
QCOMPARE(info.firstPartyUrl, requestUrl);
@@ -456,6 +463,7 @@ void tst_QWebEngineUrlRequestInterceptor::requestInterceptorByResourceType()
QTRY_COMPARE(interceptor.getUrlRequestForType(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType)).count(), 1);
QList<RequestInfo> infos = interceptor.getUrlRequestForType(static_cast<QWebEngineUrlRequestInfo::ResourceType>(resourceType));
+ QVERIFY(infos.count() >= 1);
QCOMPARE(infos.at(0).requestUrl, requestUrl);
QCOMPARE(infos.at(0).firstPartyUrl, firstPartyUrl);
QCOMPARE(infos.at(0).resourceType, resourceType);
diff --git a/tests/auto/pdf/pdf.pro b/tests/auto/pdf/pdf.pro
new file mode 100644
index 000000000..a2b3fcff2
--- /dev/null
+++ b/tests/auto/pdf/pdf.pro
@@ -0,0 +1,8 @@
+TEMPLATE = subdirs
+
+SUBDIRS = \
+ qpdfbookmarkmodel \
+ qpdfpagenavigation \
+ qpdfpagerenderer
+
+qtHaveModule(printsupport): SUBDIRS += qpdfdocument
diff --git a/tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks.pdf b/tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks.pdf
new file mode 100644
index 000000000..bd27c18b6
--- /dev/null
+++ b/tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks_pages.pdf b/tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks_pages.pdf
new file mode 100644
index 000000000..c4e1aa36e
--- /dev/null
+++ b/tests/auto/pdf/qpdfbookmarkmodel/pdf-sample.bookmarks_pages.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfbookmarkmodel/qpdfbookmarkmodel.pro b/tests/auto/pdf/qpdfbookmarkmodel/qpdfbookmarkmodel.pro
new file mode 100644
index 000000000..11a010637
--- /dev/null
+++ b/tests/auto/pdf/qpdfbookmarkmodel/qpdfbookmarkmodel.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qpdfbookmarkmodel
+QT += pdf testlib network
+macos:CONFIG -= app_bundle
+SOURCES += tst_qpdfbookmarkmodel.cpp
diff --git a/tests/auto/pdf/qpdfbookmarkmodel/tst_qpdfbookmarkmodel.cpp b/tests/auto/pdf/qpdfbookmarkmodel/tst_qpdfbookmarkmodel.cpp
new file mode 100644
index 000000000..fddc98011
--- /dev/null
+++ b/tests/auto/pdf/qpdfbookmarkmodel/tst_qpdfbookmarkmodel.cpp
@@ -0,0 +1,287 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QPdfDocument>
+#include <QPdfBookmarkModel>
+
+class tst_QPdfBookmarkModel: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QPdfBookmarkModel()
+ {
+ qRegisterMetaType<QPdfDocument::Status>();
+ }
+
+private slots:
+ void emptyModel();
+ void setEmptyDocument();
+ void setEmptyDocumentAndLoad();
+ void setLoadedDocument();
+ void unloadDocument();
+ void testTreeStructure();
+ void testListStructure();
+ void testPageNumberRole();
+};
+
+void tst_QPdfBookmarkModel::emptyModel()
+{
+ QPdfBookmarkModel model;
+
+ QVERIFY(!model.document());
+ QCOMPARE(model.structureMode(), QPdfBookmarkModel::TreeMode);
+ QCOMPARE(model.rowCount(), 0);
+ QCOMPARE(model.columnCount(), 1);
+ QCOMPARE(model.index(0, 0).isValid(), false);
+}
+
+void tst_QPdfBookmarkModel::setEmptyDocument()
+{
+ QPdfDocument document;
+ QPdfBookmarkModel model;
+
+ model.setDocument(&document);
+
+ QCOMPARE(model.document(), &document);
+ QCOMPARE(model.structureMode(), QPdfBookmarkModel::TreeMode);
+ QCOMPARE(model.rowCount(), 0);
+ QCOMPARE(model.columnCount(), 1);
+ QCOMPARE(model.index(0, 0).isValid(), false);
+}
+
+void tst_QPdfBookmarkModel::setEmptyDocumentAndLoad()
+{
+ QPdfDocument document;
+ QPdfBookmarkModel model;
+
+ model.setDocument(&document);
+
+ QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
+ QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
+
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError);
+
+ QCOMPARE(modelAboutToBeResetSpy.count(), 1);
+ QCOMPARE(modelResetSpy.count(), 1);
+
+ QCOMPARE(model.rowCount(), 3);
+}
+
+void tst_QPdfBookmarkModel::setLoadedDocument()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError);
+
+ QPdfBookmarkModel model;
+
+ QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
+ QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
+
+ model.setDocument(&document);
+
+ QCOMPARE(modelAboutToBeResetSpy.count(), 1);
+ QCOMPARE(modelResetSpy.count(), 1);
+
+ QCOMPARE(model.rowCount(), 3);
+}
+
+void tst_QPdfBookmarkModel::unloadDocument()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError);
+
+ QPdfBookmarkModel model;
+ model.setDocument(&document);
+
+ QCOMPARE(model.rowCount(), 3);
+
+ QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
+ QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
+
+ document.close();
+
+ QCOMPARE(modelAboutToBeResetSpy.count(), 1);
+ QCOMPARE(modelResetSpy.count(), 1);
+
+ QCOMPARE(model.rowCount(), 0);
+}
+
+void tst_QPdfBookmarkModel::testTreeStructure()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError);
+
+ QPdfBookmarkModel model;
+ model.setDocument(&document);
+
+ QCOMPARE(model.rowCount(), 3);
+
+ const QModelIndex index1 = model.index(0, 0);
+ QCOMPARE(index1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1"));
+ QCOMPARE(index1.data(QPdfBookmarkModel::LevelRole).toInt(), 0);
+ QCOMPARE(model.rowCount(index1), 2);
+
+ const QModelIndex index1_1 = model.index(0, 0, index1);
+ QCOMPARE(index1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.1"));
+ QCOMPARE(index1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index1_1), 0);
+
+ const QModelIndex index1_2 = model.index(1, 0, index1);
+ QCOMPARE(index1_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.2"));
+ QCOMPARE(index1_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index1_2), 0);
+
+ const QModelIndex index2 = model.index(1, 0);
+ QCOMPARE(index2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2"));
+ QCOMPARE(index2.data(QPdfBookmarkModel::LevelRole).toInt(), 0);
+ QCOMPARE(model.rowCount(index2), 2);
+
+ const QModelIndex index2_1 = model.index(0, 0, index2);
+ QCOMPARE(index2_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1"));
+ QCOMPARE(index2_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index2_1), 1);
+
+ const QModelIndex index2_1_1 = model.index(0, 0, index2_1);
+ QCOMPARE(index2_1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1.1"));
+ QCOMPARE(index2_1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 2);
+ QCOMPARE(model.rowCount(index2_1_1), 0);
+
+ const QModelIndex index2_2 = model.index(1, 0, index2);
+ QCOMPARE(index2_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.2"));
+ QCOMPARE(index2_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index2_2), 0);
+
+ const QModelIndex index3 = model.index(2, 0);
+ QCOMPARE(index3.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 3"));
+ QCOMPARE(index3.data(QPdfBookmarkModel::LevelRole).toInt(), 0);
+ QCOMPARE(model.rowCount(index3), 0);
+
+ const QModelIndex index4 = model.index(3, 0);
+ QCOMPARE(index4, QModelIndex());
+}
+
+void tst_QPdfBookmarkModel::testListStructure()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks.pdf")), QPdfDocument::NoError);
+
+ QPdfBookmarkModel model;
+ model.setDocument(&document);
+
+ QSignalSpy modelAboutToBeResetSpy(&model, SIGNAL(modelAboutToBeReset()));
+ QSignalSpy modelResetSpy(&model, SIGNAL(modelReset()));
+
+ model.setStructureMode(QPdfBookmarkModel::ListMode);
+
+ QCOMPARE(modelAboutToBeResetSpy.count(), 1);
+ QCOMPARE(modelResetSpy.count(), 1);
+
+ QCOMPARE(model.rowCount(), 8);
+
+ const QModelIndex index1 = model.index(0, 0);
+ QCOMPARE(index1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1"));
+ QCOMPARE(index1.data(QPdfBookmarkModel::LevelRole).toInt(), 0);
+ QCOMPARE(model.rowCount(index1), 0);
+
+ const QModelIndex index1_1 = model.index(1, 0);
+ QCOMPARE(index1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.1"));
+ QCOMPARE(index1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index1_1), 0);
+
+ const QModelIndex index1_2 = model.index(2, 0);
+ QCOMPARE(index1_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 1.2"));
+ QCOMPARE(index1_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index1_2), 0);
+
+ const QModelIndex index2 = model.index(3, 0);
+ QCOMPARE(index2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2"));
+ QCOMPARE(index2.data(QPdfBookmarkModel::LevelRole).toInt(), 0);
+ QCOMPARE(model.rowCount(index2), 0);
+
+ const QModelIndex index2_1 = model.index(4, 0);
+ QCOMPARE(index2_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1"));
+ QCOMPARE(index2_1.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index2_1), 0);
+
+ const QModelIndex index2_1_1 = model.index(5, 0);
+ QCOMPARE(index2_1_1.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.1.1"));
+ QCOMPARE(index2_1_1.data(QPdfBookmarkModel::LevelRole).toInt(), 2);
+ QCOMPARE(model.rowCount(index2_1_1), 0);
+
+ const QModelIndex index2_2 = model.index(6, 0);
+ QCOMPARE(index2_2.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 2.2"));
+ QCOMPARE(index2_2.data(QPdfBookmarkModel::LevelRole).toInt(), 1);
+ QCOMPARE(model.rowCount(index2_2), 0);
+
+ const QModelIndex index3 = model.index(7, 0);
+ QCOMPARE(index3.data(QPdfBookmarkModel::TitleRole).toString(), QLatin1String("Section 3"));
+ QCOMPARE(index3.data(QPdfBookmarkModel::LevelRole).toInt(), 0);
+ QCOMPARE(model.rowCount(index3), 0);
+
+ const QModelIndex index4 = model.index(8, 0);
+ QCOMPARE(index4, QModelIndex());
+}
+
+void tst_QPdfBookmarkModel::testPageNumberRole()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.bookmarks_pages.pdf")), QPdfDocument::NoError);
+
+ QPdfBookmarkModel model;
+ model.setDocument(&document);
+
+ QCOMPARE(model.rowCount(), 3);
+
+ const QModelIndex index1 = model.index(0, 0);
+ QCOMPARE(index1.data(QPdfBookmarkModel::PageNumberRole).toInt(), 0);
+
+ const QModelIndex index2 = model.index(1, 0);
+ QCOMPARE(index2.data(QPdfBookmarkModel::PageNumberRole).toInt(), 1);
+
+ const QModelIndex index2_1 = model.index(0, 0, index2);
+ QCOMPARE(index2_1.data(QPdfBookmarkModel::PageNumberRole).toInt(), 1);
+
+ const QModelIndex index3 = model.index(2, 0);
+ QCOMPARE(index3.data(QPdfBookmarkModel::PageNumberRole).toInt(), 2);
+}
+
+QTEST_MAIN(tst_QPdfBookmarkModel)
+
+#include "tst_qpdfbookmarkmodel.moc"
diff --git a/tests/auto/pdf/qpdfdocument/BLACKLIST b/tests/auto/pdf/qpdfdocument/BLACKLIST
new file mode 100644
index 000000000..b8db556d6
--- /dev/null
+++ b/tests/auto/pdf/qpdfdocument/BLACKLIST
@@ -0,0 +1,6 @@
+[password]
+*
+
+[passwordClearedOnClose]
+*
+
diff --git a/tests/auto/pdf/qpdfdocument/pdf-sample.metadata.pdf b/tests/auto/pdf/qpdfdocument/pdf-sample.metadata.pdf
new file mode 100644
index 000000000..c3350ba5f
--- /dev/null
+++ b/tests/auto/pdf/qpdfdocument/pdf-sample.metadata.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfdocument/pdf-sample.protected.pdf b/tests/auto/pdf/qpdfdocument/pdf-sample.protected.pdf
new file mode 100644
index 000000000..d76fdd1a6
--- /dev/null
+++ b/tests/auto/pdf/qpdfdocument/pdf-sample.protected.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfdocument/qpdfdocument.pro b/tests/auto/pdf/qpdfdocument/qpdfdocument.pro
new file mode 100644
index 000000000..8382a25e3
--- /dev/null
+++ b/tests/auto/pdf/qpdfdocument/qpdfdocument.pro
@@ -0,0 +1,6 @@
+CONFIG += testcase
+TARGET = tst_qpdfdocument
+QT += pdf printsupport testlib network
+macx:CONFIG -= app_bundle
+SOURCES += tst_qpdfdocument.cpp
+
diff --git a/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp b/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp
new file mode 100644
index 000000000..29b85fc89
--- /dev/null
+++ b/tests/auto/pdf/qpdfdocument/tst_qpdfdocument.cpp
@@ -0,0 +1,386 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QPainter>
+#include <QPdfDocument>
+#include <QPrinter>
+#include <QTemporaryFile>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+class tst_QPdfDocument: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QPdfDocument()
+ {
+ qRegisterMetaType<QPdfDocument::Status>();
+ }
+
+private slots:
+ void pageCount();
+ void loadFromIODevice();
+ void loadAsync();
+ void password();
+ void close();
+ void loadAfterClose();
+ void closeOnDestroy();
+ void status();
+ void passwordClearedOnClose();
+ void metaData();
+};
+
+struct TemporaryPdf: public QTemporaryFile
+{
+ TemporaryPdf();
+ QPageLayout pageLayout;
+};
+
+
+TemporaryPdf::TemporaryPdf()
+{
+ open();
+ pageLayout = QPageLayout(QPageSize(QPageSize::A4), QPageLayout::Portrait, QMarginsF());
+
+ {
+ QPrinter printer;
+ printer.setOutputFormat(QPrinter::PdfFormat);
+ printer.setOutputFileName(fileName());
+ printer.setPageLayout(pageLayout);
+
+ {
+ QPainter painter(&printer);
+ painter.drawText(100, 100, QStringLiteral("Hello Page 1"));
+ printer.newPage();
+ painter.drawText(100, 100, QStringLiteral("Hello Page 2"));
+ }
+ }
+
+ seek(0);
+}
+
+void tst_QPdfDocument::pageCount()
+{
+ TemporaryPdf tempPdf;
+
+ QPdfDocument doc;
+ QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int)));
+
+ QCOMPARE(doc.pageCount(), 0);
+ QCOMPARE(doc.load(tempPdf.fileName()), QPdfDocument::NoError);
+ QCOMPARE(doc.pageCount(), 2);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+
+ QCOMPARE(doc.pageSize(0).toSize(), tempPdf.pageLayout.fullRectPoints().size());
+}
+
+void tst_QPdfDocument::loadFromIODevice()
+{
+ TemporaryPdf tempPdf;
+ QPdfDocument doc;
+ QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+ QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int)));
+ doc.load(&tempPdf);
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Ready);
+ QCOMPARE(doc.error(), QPdfDocument::NoError);
+ QCOMPARE(doc.pageCount(), 2);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+}
+
+void tst_QPdfDocument::loadAsync()
+{
+ TemporaryPdf tempPdf;
+
+ QNetworkAccessManager nam;
+
+ QUrl url = QUrl::fromLocalFile(tempPdf.fileName());
+ QScopedPointer<QNetworkReply> reply(nam.get(QNetworkRequest(url)));
+
+ QPdfDocument doc;
+ QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+ QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int)));
+
+ doc.load(reply.data());
+
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Ready);
+ QCOMPARE(doc.pageCount(), 2);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+}
+
+void tst_QPdfDocument::password()
+{
+ QPdfDocument doc;
+ QSignalSpy passwordChangedSpy(&doc, SIGNAL(passwordChanged()));
+
+ QCOMPARE(doc.pageCount(), 0);
+ QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::IncorrectPasswordError);
+ QCOMPARE(passwordChangedSpy.count(), 0);
+ doc.setPassword(QStringLiteral("WrongPassword"));
+ QCOMPARE(passwordChangedSpy.count(), 1);
+ QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::IncorrectPasswordError);
+ QCOMPARE(doc.status(), QPdfDocument::Error);
+ doc.setPassword(QStringLiteral("Qt"));
+ QCOMPARE(passwordChangedSpy.count(), 2);
+ QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::NoError);
+ QCOMPARE(doc.pageCount(), 1);
+}
+
+void tst_QPdfDocument::close()
+{
+ TemporaryPdf tempPdf;
+ QPdfDocument doc;
+
+ QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+ QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int)));
+
+ doc.load(&tempPdf);
+
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Ready);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+
+ statusChangedSpy.clear();
+ pageCountChangedSpy.clear();
+
+ doc.close();
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Unloading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Null);
+ QCOMPARE(doc.pageCount(), 0);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+}
+
+void tst_QPdfDocument::loadAfterClose()
+{
+ TemporaryPdf tempPdf;
+ QPdfDocument doc;
+
+ QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+ QSignalSpy pageCountChangedSpy(&doc, SIGNAL(pageCountChanged(int)));
+
+ doc.load(&tempPdf);
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Ready);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+ statusChangedSpy.clear();
+ pageCountChangedSpy.clear();
+
+ doc.close();
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Unloading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Null);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+ statusChangedSpy.clear();
+ pageCountChangedSpy.clear();
+
+ doc.load(&tempPdf);
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Ready);
+ QCOMPARE(doc.error(), QPdfDocument::NoError);
+ QCOMPARE(doc.pageCount(), 2);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), doc.pageCount());
+}
+
+void tst_QPdfDocument::closeOnDestroy()
+{
+ TemporaryPdf tempPdf;
+
+ // deleting an open document should automatically close it
+ {
+ QPdfDocument *doc = new QPdfDocument;
+
+ doc->load(&tempPdf);
+
+ QSignalSpy statusChangedSpy(doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+ QSignalSpy pageCountChangedSpy(doc, SIGNAL(pageCountChanged(int)));
+
+ delete doc;
+
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Unloading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Null);
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), 0);
+ }
+
+ // deleting a closed document should not emit any signal
+ {
+ QPdfDocument *doc = new QPdfDocument;
+ doc->load(&tempPdf);
+ doc->close();
+
+ QSignalSpy statusChangedSpy(doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+ QSignalSpy pageCountChangedSpy(doc, SIGNAL(pageCountChanged(int)));
+
+ delete doc;
+
+ QCOMPARE(statusChangedSpy.count(), 0);
+ QCOMPARE(pageCountChangedSpy.count(), 0);
+ }
+}
+
+void tst_QPdfDocument::status()
+{
+ TemporaryPdf tempPdf;
+
+ QPdfDocument doc;
+ QCOMPARE(doc.status(), QPdfDocument::Null);
+
+ QSignalSpy statusChangedSpy(&doc, SIGNAL(statusChanged(QPdfDocument::Status)));
+
+ // open existing document
+ doc.load(&tempPdf);
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Ready);
+ statusChangedSpy.clear();
+
+ QCOMPARE(doc.status(), QPdfDocument::Ready);
+
+ // close document
+ doc.close();
+
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Unloading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Null);
+ statusChangedSpy.clear();
+
+ QCOMPARE(doc.status(), QPdfDocument::Null);
+
+ // try to open non-existing document
+ doc.load(QFINDTESTDATA("does-not-exist.pdf"));
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Error);
+ QCOMPARE(doc.status(), QPdfDocument::Error);
+ statusChangedSpy.clear();
+
+ // try to open non-existing document asynchronously
+ QNetworkAccessManager accessManager;
+
+ const QUrl url("http://doesnotexist.qt.io");
+ QScopedPointer<QNetworkReply> reply(accessManager.get(QNetworkRequest(url)));
+
+ doc.load(reply.data());
+
+ QElapsedTimer stopWatch;
+ stopWatch.start();
+ forever {
+ QCoreApplication::instance()->processEvents();
+ if (statusChangedSpy.count() == 2)
+ break;
+ if (stopWatch.elapsed() >= 30000)
+ break;
+ }
+
+ QCOMPARE(statusChangedSpy.count(), 2);
+ QCOMPARE(statusChangedSpy[0][0].value<QPdfDocument::Status>(), QPdfDocument::Loading);
+ QCOMPARE(statusChangedSpy[1][0].value<QPdfDocument::Status>(), QPdfDocument::Error);
+ statusChangedSpy.clear();
+}
+
+void tst_QPdfDocument::passwordClearedOnClose()
+{
+ TemporaryPdf tempPdf;
+ QPdfDocument doc;
+
+ QSignalSpy passwordChangedSpy(&doc, SIGNAL(passwordChanged()));
+
+ doc.setPassword(QStringLiteral("Qt"));
+ QCOMPARE(passwordChangedSpy.count(), 1);
+ QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.protected.pdf")), QPdfDocument::NoError);
+ passwordChangedSpy.clear();
+
+ doc.close(); // password is cleared on close
+ QCOMPARE(passwordChangedSpy.count(), 1);
+ passwordChangedSpy.clear();
+
+ doc.load(&tempPdf);
+ doc.close(); // signal is not emitted if password didn't change
+ QCOMPARE(passwordChangedSpy.count(), 0);
+}
+
+void tst_QPdfDocument::metaData()
+{
+ QPdfDocument doc;
+
+ // a closed document does not return any meta data
+ QCOMPARE(doc.metaData(QPdfDocument::Title).toString(), QString());
+ QCOMPARE(doc.metaData(QPdfDocument::Subject).toString(), QString());
+ QCOMPARE(doc.metaData(QPdfDocument::Author).toString(), QString());
+ QCOMPARE(doc.metaData(QPdfDocument::Keywords).toString(), QString());
+ QCOMPARE(doc.metaData(QPdfDocument::Producer).toString(), QString());
+ QCOMPARE(doc.metaData(QPdfDocument::Creator).toString(), QString());
+ QCOMPARE(doc.metaData(QPdfDocument::CreationDate).toDateTime(), QDateTime());
+ QCOMPARE(doc.metaData(QPdfDocument::ModificationDate).toDateTime(), QDateTime());
+
+ QCOMPARE(doc.load(QFINDTESTDATA("pdf-sample.metadata.pdf")), QPdfDocument::NoError);
+
+ // check for proper meta data from sample document
+ QCOMPARE(doc.metaData(QPdfDocument::Title).toString(), QString::fromLatin1("Qt PDF Unit Test Document"));
+ QCOMPARE(doc.metaData(QPdfDocument::Subject).toString(), QString::fromLatin1("A test for meta data access"));
+ QCOMPARE(doc.metaData(QPdfDocument::Author).toString(), QString::fromLatin1("John Doe"));
+ QCOMPARE(doc.metaData(QPdfDocument::Keywords).toString(), QString::fromLatin1("meta data keywords"));
+ QCOMPARE(doc.metaData(QPdfDocument::Producer).toString(), QString::fromLatin1("LibreOffice 5.1"));
+ QCOMPARE(doc.metaData(QPdfDocument::Creator).toString(), QString::fromLatin1("Writer"));
+ QCOMPARE(doc.metaData(QPdfDocument::CreationDate).toDateTime(), QDateTime(QDate(2016, 8, 7), QTime(7, 3, 6), Qt::UTC));
+ QCOMPARE(doc.metaData(QPdfDocument::ModificationDate).toDateTime(), QDateTime(QDate(2016, 8, 8), QTime(8, 3, 6), Qt::UTC));
+}
+
+QTEST_MAIN(tst_QPdfDocument)
+
+#include "tst_qpdfdocument.moc"
+
diff --git a/tests/auto/pdf/qpdfpagenavigation/pdf-sample.pagenavigation.pdf b/tests/auto/pdf/qpdfpagenavigation/pdf-sample.pagenavigation.pdf
new file mode 100644
index 000000000..c4e1aa36e
--- /dev/null
+++ b/tests/auto/pdf/qpdfpagenavigation/pdf-sample.pagenavigation.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfpagenavigation/qpdfpagenavigation.pro b/tests/auto/pdf/qpdfpagenavigation/qpdfpagenavigation.pro
new file mode 100644
index 000000000..8de99543f
--- /dev/null
+++ b/tests/auto/pdf/qpdfpagenavigation/qpdfpagenavigation.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qpdfpagenavigation
+QT += pdf testlib network
+macos:CONFIG -= app_bundle
+SOURCES += tst_qpdfpagenavigation.cpp
diff --git a/tests/auto/pdf/qpdfpagenavigation/tst_qpdfpagenavigation.cpp b/tests/auto/pdf/qpdfpagenavigation/tst_qpdfpagenavigation.cpp
new file mode 100644
index 000000000..ff6a02750
--- /dev/null
+++ b/tests/auto/pdf/qpdfpagenavigation/tst_qpdfpagenavigation.cpp
@@ -0,0 +1,200 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QPdfDocument>
+#include <QPdfPageNavigation>
+
+class tst_QPdfPageNavigation: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void defaultValues();
+ void setEmptyDocument();
+ void setEmptyDocumentAndLoad();
+ void setLoadedDocument();
+ void unloadDocument();
+ void navigate();
+};
+
+void tst_QPdfPageNavigation::defaultValues()
+{
+ QPdfPageNavigation pageNavigation;
+
+ QCOMPARE(pageNavigation.document(), nullptr);
+ QCOMPARE(pageNavigation.currentPage(), 0);
+ QCOMPARE(pageNavigation.pageCount(), 0);
+ QCOMPARE(pageNavigation.canGoToPreviousPage(), false);
+ QCOMPARE(pageNavigation.canGoToNextPage(), false);
+}
+
+void tst_QPdfPageNavigation::setEmptyDocument()
+{
+ QPdfDocument document;
+ QPdfPageNavigation pageNavigation;
+
+ pageNavigation.setDocument(&document);
+
+ QCOMPARE(pageNavigation.document(), &document);
+ QCOMPARE(pageNavigation.currentPage(), 0);
+ QCOMPARE(pageNavigation.pageCount(), 0);
+ QCOMPARE(pageNavigation.canGoToPreviousPage(), false);
+ QCOMPARE(pageNavigation.canGoToNextPage(), false);
+}
+
+void tst_QPdfPageNavigation::setEmptyDocumentAndLoad()
+{
+ QPdfDocument document;
+ QPdfPageNavigation pageNavigation;
+
+ pageNavigation.setDocument(&document);
+
+ QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged);
+ QSignalSpy pageCountChangedSpy(&pageNavigation, &QPdfPageNavigation::pageCountChanged);
+ QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged);
+ QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged);
+
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError);
+
+ QCOMPARE(currentPageChangedSpy.count(), 0); // current page stays '0'
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), 3);
+ QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); // still no previous page available
+ QCOMPARE(canGoToNextPageChangedSpy.count(), 1);
+ QCOMPARE(canGoToNextPageChangedSpy[0][0].toBool(), true);
+}
+
+void tst_QPdfPageNavigation::setLoadedDocument()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError);
+
+ QPdfPageNavigation pageNavigation;
+
+ QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged);
+ QSignalSpy pageCountChangedSpy(&pageNavigation, &QPdfPageNavigation::pageCountChanged);
+ QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged);
+ QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged);
+
+ pageNavigation.setDocument(&document);
+
+ QCOMPARE(currentPageChangedSpy.count(), 0); // current page stays '0'
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), 3);
+ QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); // still no previous page available
+ QCOMPARE(canGoToNextPageChangedSpy.count(), 1);
+ QCOMPARE(canGoToNextPageChangedSpy[0][0].toBool(), true);
+}
+
+void tst_QPdfPageNavigation::unloadDocument()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError);
+
+ QPdfPageNavigation pageNavigation;
+ pageNavigation.setDocument(&document);
+
+ QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged);
+ QSignalSpy pageCountChangedSpy(&pageNavigation, &QPdfPageNavigation::pageCountChanged);
+ QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged);
+ QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged);
+
+ document.close();
+
+ QCOMPARE(currentPageChangedSpy.count(), 0); // current page stays '0'
+ QCOMPARE(pageCountChangedSpy.count(), 1);
+ QCOMPARE(pageCountChangedSpy[0][0].toInt(), 0);
+ QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0); // still no previous page available
+ QCOMPARE(canGoToNextPageChangedSpy.count(), 1);
+ QCOMPARE(canGoToNextPageChangedSpy[0][0].toBool(), false);
+}
+
+void tst_QPdfPageNavigation::navigate()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagenavigation.pdf")), QPdfDocument::NoError);
+
+ QPdfPageNavigation pageNavigation;
+ pageNavigation.setDocument(&document);
+
+ QSignalSpy currentPageChangedSpy(&pageNavigation, &QPdfPageNavigation::currentPageChanged);
+ QSignalSpy canGoToPreviousPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToPreviousPageChanged);
+ QSignalSpy canGoToNextPageChangedSpy(&pageNavigation, &QPdfPageNavigation::canGoToNextPageChanged);
+
+ QCOMPARE(pageNavigation.currentPage(), 0);
+
+ // try to go to previous page while there is none
+ QCOMPARE(pageNavigation.canGoToPreviousPage(), false);
+ pageNavigation.goToPreviousPage();
+ QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0);
+ QCOMPARE(pageNavigation.currentPage(), 0);
+ QCOMPARE(pageNavigation.canGoToPreviousPage(), false);
+
+ // try to go to next page
+ QCOMPARE(pageNavigation.canGoToNextPage(), true);
+ pageNavigation.goToNextPage();
+ QCOMPARE(canGoToPreviousPageChangedSpy.count(), 1);
+ QCOMPARE(canGoToNextPageChangedSpy.count(), 0);
+ QCOMPARE(currentPageChangedSpy.count(), 1);
+ QCOMPARE(pageNavigation.currentPage(), 1);
+ QCOMPARE(pageNavigation.canGoToPreviousPage(), true);
+
+ currentPageChangedSpy.clear();
+ canGoToPreviousPageChangedSpy.clear();
+ canGoToNextPageChangedSpy.clear();
+
+ // try to go to last page
+ pageNavigation.setCurrentPage(2);
+ QCOMPARE(canGoToPreviousPageChangedSpy.count(), 0);
+ QCOMPARE(canGoToNextPageChangedSpy.count(), 1);
+ QCOMPARE(currentPageChangedSpy.count(), 1);
+ QCOMPARE(pageNavigation.currentPage(), 2);
+ QCOMPARE(pageNavigation.canGoToNextPage(), false);
+
+ // check that invalid requests are ignored
+ pageNavigation.setCurrentPage(-1);
+ QCOMPARE(pageNavigation.currentPage(), 2);
+
+ pageNavigation.setCurrentPage(3);
+ QCOMPARE(pageNavigation.currentPage(), 2);
+}
+
+QTEST_MAIN(tst_QPdfPageNavigation)
+
+#include "tst_qpdfpagenavigation.moc"
diff --git a/tests/auto/pdf/qpdfpagerenderer/pdf-sample.pagerenderer.pdf b/tests/auto/pdf/qpdfpagerenderer/pdf-sample.pagerenderer.pdf
new file mode 100644
index 000000000..c4e1aa36e
--- /dev/null
+++ b/tests/auto/pdf/qpdfpagerenderer/pdf-sample.pagerenderer.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfpagerenderer/qpdfpagerenderer.pro b/tests/auto/pdf/qpdfpagerenderer/qpdfpagerenderer.pro
new file mode 100644
index 000000000..9ccb4e82c
--- /dev/null
+++ b/tests/auto/pdf/qpdfpagerenderer/qpdfpagerenderer.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qpdfpagerenderer
+QT += pdf testlib network
+macos:CONFIG -= app_bundle
+SOURCES += tst_qpdfpagerenderer.cpp
diff --git a/tests/auto/pdf/qpdfpagerenderer/tst_qpdfpagerenderer.cpp b/tests/auto/pdf/qpdfpagerenderer/tst_qpdfpagerenderer.cpp
new file mode 100644
index 000000000..534fbd9ce
--- /dev/null
+++ b/tests/auto/pdf/qpdfpagerenderer/tst_qpdfpagerenderer.cpp
@@ -0,0 +1,184 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Tobias König <tobias.koenig@kdab.com>
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the QtPDF module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QPdfDocument>
+#include <QPdfPageRenderer>
+
+#include <QtTest/QtTest>
+
+class tst_QPdfPageRenderer: public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void defaultValues();
+ void withNoDocument();
+ void withEmptyDocument();
+ void withLoadedDocumentSingleThreaded();
+ void withLoadedDocumentMultiThreaded();
+ void switchingRenderMode();
+};
+
+void tst_QPdfPageRenderer::defaultValues()
+{
+ QPdfPageRenderer pageRenderer;
+
+ QCOMPARE(pageRenderer.document(), nullptr);
+ QCOMPARE(pageRenderer.renderMode(), QPdfPageRenderer::RenderMode::SingleThreaded);
+}
+
+void tst_QPdfPageRenderer::withNoDocument()
+{
+ QPdfPageRenderer pageRenderer;
+
+ const QSize imageSize(100, 100);
+ const quint64 requestId = pageRenderer.requestPage(0, imageSize);
+
+ QCOMPARE(requestId, quint64(0));
+}
+
+void tst_QPdfPageRenderer::withEmptyDocument()
+{
+ QPdfDocument document;
+ QPdfPageRenderer pageRenderer;
+
+ pageRenderer.setDocument(&document);
+
+ const QSize imageSize(100, 100);
+ const quint64 requestId = pageRenderer.requestPage(0, imageSize);
+
+ QCOMPARE(requestId, quint64(0));
+}
+
+void tst_QPdfPageRenderer::withLoadedDocumentSingleThreaded()
+{
+ QPdfDocument document;
+ QPdfPageRenderer pageRenderer;
+ pageRenderer.setDocument(&document);
+
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagerenderer.pdf")), QPdfDocument::NoError);
+
+ QSignalSpy pageRenderedSpy(&pageRenderer, &QPdfPageRenderer::pageRendered);
+
+ const QSize imageSize(100, 100);
+ const quint64 requestId = pageRenderer.requestPage(0, imageSize);
+
+ QCOMPARE(requestId, quint64(1));
+ QTRY_COMPARE(pageRenderedSpy.count(), 1);
+ QCOMPARE(pageRenderedSpy[0][0].toInt(), 0);
+ QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>().size(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][4].toULongLong(), requestId);
+}
+
+void tst_QPdfPageRenderer::withLoadedDocumentMultiThreaded()
+{
+ QPdfDocument document;
+
+ QPdfPageRenderer pageRenderer;
+ pageRenderer.setDocument(&document);
+ pageRenderer.setRenderMode(QPdfPageRenderer::RenderMode::MultiThreaded);
+
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagerenderer.pdf")), QPdfDocument::NoError);
+
+ QSignalSpy pageRenderedSpy(&pageRenderer, &QPdfPageRenderer::pageRendered);
+
+ const QSize imageSize(100, 100);
+ const quint64 requestId = pageRenderer.requestPage(0, imageSize);
+
+ QCOMPARE(requestId, quint64(1));
+ QTRY_COMPARE(pageRenderedSpy.count(), 1);
+ QCOMPARE(pageRenderedSpy[0][0].toInt(), 0);
+ QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>().size(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][4].toULongLong(), requestId);
+}
+
+void tst_QPdfPageRenderer::switchingRenderMode()
+{
+ QPdfDocument document;
+ QPdfPageRenderer pageRenderer;
+ pageRenderer.setDocument(&document);
+
+ QCOMPARE(document.load(QFINDTESTDATA("pdf-sample.pagerenderer.pdf")), QPdfDocument::NoError);
+
+ QSignalSpy pageRenderedSpy(&pageRenderer, &QPdfPageRenderer::pageRendered);
+
+ // render single threaded
+ const QSize imageSize(100, 100);
+ const quint64 firstRequestId = pageRenderer.requestPage(0, imageSize);
+
+ QTRY_COMPARE(pageRenderedSpy.count(), 1);
+ QCOMPARE(pageRenderedSpy[0][0].toInt(), 0);
+ QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>().size(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][4].toULongLong(), firstRequestId);
+
+ const QImage image = pageRenderedSpy[0][2].value<QImage>();
+
+ pageRenderedSpy.clear();
+
+ // switch to multi threaded
+ pageRenderer.setRenderMode(QPdfPageRenderer::RenderMode::MultiThreaded);
+
+ const quint64 secondRequestId = pageRenderer.requestPage(0, imageSize);
+
+ QVERIFY(firstRequestId != secondRequestId);
+ QTRY_COMPARE(pageRenderedSpy.count(), 1);
+ QCOMPARE(pageRenderedSpy[0][0].toInt(), 0);
+ QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>(), image);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>().size(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][4].toULongLong(), secondRequestId);
+
+ pageRenderedSpy.clear();
+
+ // switch back to single threaded
+ pageRenderer.setRenderMode(QPdfPageRenderer::RenderMode::SingleThreaded);
+
+ const quint64 thirdRequestId = pageRenderer.requestPage(0, imageSize);
+
+ QTRY_COMPARE(pageRenderedSpy.count(), 1);
+ QCOMPARE(pageRenderedSpy[0][0].toInt(), 0);
+ QCOMPARE(pageRenderedSpy[0][1].toSize(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>(), image);
+ QCOMPARE(pageRenderedSpy[0][2].value<QImage>().size(), imageSize);
+ QCOMPARE(pageRenderedSpy[0][4].toULongLong(), thirdRequestId);
+}
+
+QTEST_MAIN(tst_QPdfPageRenderer)
+
+#include "tst_qpdfpagerenderer.moc"
diff --git a/tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro b/tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro
new file mode 100644
index 000000000..205fef175
--- /dev/null
+++ b/tests/auto/pdf/qpdfsearchmodel/qpdfsearchmodel.pro
@@ -0,0 +1,5 @@
+CONFIG += testcase
+TARGET = tst_qpdfsearchmodel
+QT += pdf testlib network
+macos:CONFIG -= app_bundle
+SOURCES += tst_qpdfsearchmodel.cpp
diff --git a/tests/auto/pdf/qpdfsearchmodel/test.pdf b/tests/auto/pdf/qpdfsearchmodel/test.pdf
new file mode 100644
index 000000000..a9dc1bc29
--- /dev/null
+++ b/tests/auto/pdf/qpdfsearchmodel/test.pdf
Binary files differ
diff --git a/tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp b/tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp
new file mode 100644
index 000000000..e690bfc11
--- /dev/null
+++ b/tests/auto/pdf/qpdfsearchmodel/tst_qpdfsearchmodel.cpp
@@ -0,0 +1,69 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+#include <QPdfDocument>
+#include <QPdfSearchModel>
+
+class tst_QPdfSearchModel: public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_QPdfSearchModel() {}
+
+private slots:
+ void findText();
+};
+
+void tst_QPdfSearchModel::findText()
+{
+ QPdfDocument document;
+ QCOMPARE(document.load(QFINDTESTDATA("test.pdf")), QPdfDocument::NoError);
+
+ QPdfSearchModel model;
+ model.setDocument(&document);
+ QVector<QRectF> matches = model.matches(1, "ai");
+
+ qDebug() << matches;
+ QCOMPARE(matches.count(), 3);
+}
+
+QTEST_MAIN(tst_QPdfSearchModel)
+
+#include "tst_qpdfsearchmodel.moc"
diff --git a/tests/auto/quick/publicapi/tst_publicapi.cpp b/tests/auto/quick/publicapi/tst_publicapi.cpp
index 321972057..aaca7997b 100644
--- a/tests/auto/quick/publicapi/tst_publicapi.cpp
+++ b/tests/auto/quick/publicapi/tst_publicapi.cpp
@@ -300,6 +300,7 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineFullScreenRequest.reject() --> void"
<< "QQuickWebEngineFullScreenRequest.toggleOn --> bool"
<< "QQuickWebEngineHistory.backItems --> QQuickWebEngineHistoryListModel*"
+ << "QQuickWebEngineHistory.clear() --> void"
<< "QQuickWebEngineHistory.forwardItems --> QQuickWebEngineHistoryListModel*"
<< "QQuickWebEngineHistory.items --> QQuickWebEngineHistoryListModel*"
<< "QQuickWebEngineJavaScriptDialogRequest.DialogTypeAlert --> DialogType"
@@ -740,6 +741,8 @@ static const QStringList expectedAPI = QStringList()
<< "QQuickWebEngineView.quotaRequested(QWebEngineQuotaRequest) --> void"
<< "QQuickWebEngineView.recentlyAudible --> bool"
<< "QQuickWebEngineView.recentlyAudibleChanged(bool) --> void"
+ << "QQuickWebEngineView.renderProcessPid --> qlonglong"
+ << "QQuickWebEngineView.renderProcessPidChanged(qlonglong) --> void"
<< "QQuickWebEngineView.recommendedState --> LifecycleState"
<< "QQuickWebEngineView.recommendedStateChanged(LifecycleState) --> void"
<< "QQuickWebEngineView.registerProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest) --> void"
diff --git a/tests/auto/quick/qmltests/data/test4.html b/tests/auto/quick/qmltests/data/test4.html
index afda71bc5..c9b395ee5 100644
--- a/tests/auto/quick/qmltests/data/test4.html
+++ b/tests/auto/quick/qmltests/data/test4.html
@@ -24,106 +24,106 @@
}
</script>
<div id="content">
- bla00<br/>
- bla01<br/>
- bla02<br/>
- bla03<br/>
- bla04<br/>
- bla05<br/>
- bla06<br/>
- bla07<br/>
- bla08<br/>
- bla09<br/>
- bla10<br/>
- bla11<br/>
- bla12<br/>
- bla13<br/>
- bla14<br/>
- bla15<br/>
- bla16<br/>
- bla17<br/>
- bla18<br/>
- bla19<br/>
- bla20<br/>
- bla21<br/>
- bla22<br/>
- bla23<br/>
- bla24<br/>
- bla25<br/>
- bla26<br/>
- bla27<br/>
- bla28<br/>
- bla29<br/>
- bla30<br/>
- bla31<br/>
- bla32<br/>
- bla33<br/>
- bla34<br/>
- bla35<br/>
- bla36<br/>
- bla37<br/>
- bla38<br/>
- bla39<br/>
- bla40<br/>
- bla41<br/>
- bla42<br/>
- bla43<br/>
- bla44<br/>
- bla45<br/>
- bla46<br/>
- bla47<br/>
- bla48<br/>
- bla49<br/>
- bla50<br/>
- bla51<br/>
- bla52<br/>
- bla53<br/>
- bla54<br/>
- bla55<br/>
- bla56<br/>
- bla57<br/>
- bla58<br/>
- bla59<br/>
- bla60<br/>
- bla61<br/>
- bla62<br/>
- bla63<br/>
- bla64<br/>
- bla65<br/>
- bla66<br/>
- bla67<br/>
- bla68<br/>
- bla69<br/>
- bla70<br/>
- bla71<br/>
- bla72<br/>
- bla73<br/>
- bla74<br/>
- bla75<br/>
- bla76<br/>
- bla77<br/>
- bla78<br/>
- bla79<br/>
- bla80<br/>
- bla81<br/>
- bla82<br/>
- bla83<br/>
- bla84<br/>
- bla85<br/>
- bla86<br/>
- bla87<br/>
- bla88<br/>
- bla89<br/>
- bla90<br/>
- bla91<br/>
- bla92<br/>
- bla93<br/>
- bla94<br/>
- bla95<br/>
- bla96<br/>
- bla97<br/>
- bla98<br/>
- bla99<br/>
+ <p>bla00
+ <p>bla01
+ <p>bla02
+ <p>bla03
+ <p>bla04
+ <p>bla05
+ <p>bla06
+ <p>bla07
+ <p>bla08
+ <p>bla09
+ <p>bla10
+ <p>bla11
+ <p>bla12
+ <p>bla13
+ <p>bla14
+ <p>bla15
+ <p>bla16
+ <p>bla17
+ <p>bla18
+ <p>bla19
+ <p>bla20
+ <p>bla21
+ <p>bla22
+ <p>bla23
+ <p>bla24
+ <p>bla25
+ <p>bla26
+ <p>bla27
+ <p>bla28
+ <p>bla29
+ <p>bla30
+ <p>bla31
+ <p>bla32
+ <p>bla33
+ <p>bla34
+ <p>bla35
+ <p>bla36
+ <p>bla37
+ <p>bla38
+ <p>bla39
+ <p>bla40
+ <p>bla41
+ <p>bla42
+ <p>bla43
+ <p>bla44
+ <p>bla45
+ <p>bla46
+ <p>bla47
+ <p>bla48
+ <p>bla49
+ <p>bla50
+ <p>bla51
+ <p>bla52
+ <p>bla53
+ <p>bla54
+ <p>bla55
+ <p>bla56
+ <p>bla57
+ <p>bla58
+ <p>bla59
+ <p>bla60
+ <p>bla61
+ <p>bla62
+ <p>bla63
+ <p>bla64
+ <p>bla65
+ <p>bla66
+ <p>bla67
+ <p>bla68
+ <p>bla69
+ <p>bla70
+ <p>bla71
+ <p>bla72
+ <p>bla73
+ <p>bla74
+ <p>bla75
+ <p>bla76
+ <p>bla77
+ <p>bla78
+ <p>bla79
+ <p>bla80
+ <p>bla81
+ <p>bla82
+ <p>bla83
+ <p>bla84
+ <p>bla85
+ <p>bla86
+ <p>bla87
+ <p>bla88
+ <p>bla89
+ <p>bla90
+ <p>bla91
+ <p>bla92
+ <p>bla93
+ <p>bla94
+ <p>bla95
+ <p>bla96
+ <p>bla97
+ <p>bla98
+ <p>bla99
</div>
</body>
</html>
diff --git a/tests/auto/quick/qmltests/data/tst_loadUrl.qml b/tests/auto/quick/qmltests/data/tst_loadUrl.qml
index 7bdd0c761..872c46641 100644
--- a/tests/auto/quick/qmltests/data/tst_loadUrl.qml
+++ b/tests/auto/quick/qmltests/data/tst_loadUrl.qml
@@ -230,7 +230,7 @@ TestWebEngineView {
compare(loadRequest.activeUrl, aboutBlank);
loadRequest = loadRequestArray[2];
compare(loadRequest.status, WebEngineView.LoadStartedStatus);
- compare(loadRequest.activeUrl, "data:text/html;charset=UTF-8,load failed");
+ compare(loadRequest.activeUrl, bogusSite);
compare(loadRequest.url, "data:text/html;charset=UTF-8,load failed")
loadRequest = loadRequestArray[3];
compare(loadRequest.status, WebEngineView.LoadSucceededStatus);
diff --git a/tests/auto/quick/qmltests/data/tst_navigationHistory.qml b/tests/auto/quick/qmltests/data/tst_navigationHistory.qml
index 77664e645..6ed232589 100644
--- a/tests/auto/quick/qmltests/data/tst_navigationHistory.qml
+++ b/tests/auto/quick/qmltests/data/tst_navigationHistory.qml
@@ -134,6 +134,13 @@ TestWebEngineView {
compare(forwardItemsList.count, 1)
compare(backItemsList.currentItem.text, Qt.resolvedUrl("test1.html"))
compare(forwardItemsList.currentItem.text, Qt.resolvedUrl("javascript.html"))
+
+ webEngineView.navigationHistory.clear()
+ compare(webEngineView.url, Qt.resolvedUrl("test2.html"))
+ compare(webEngineView.canGoBack, false)
+ compare(webEngineView.canGoForward, false)
+ compare(backItemsList.count, 0)
+ compare(forwardItemsList.count, 0)
}
}
}
diff --git a/tests/auto/quick/qquickwebengineview/BLACKLIST b/tests/auto/quick/qquickwebengineview/BLACKLIST
index e69de29bb..af97422a9 100644
--- a/tests/auto/quick/qquickwebengineview/BLACKLIST
+++ b/tests/auto/quick/qquickwebengineview/BLACKLIST
@@ -0,0 +1,3 @@
+# until qt5.git is updated with new qtdeclarative
+[focusChild]
+*
diff --git a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
index 04be25abe..5ee30f165 100644
--- a/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
+++ b/tests/auto/quick/qquickwebengineview/tst_qquickwebengineview.cpp
@@ -581,7 +581,7 @@ void tst_QQuickWebEngineView::interruptImeTextComposition()
QFETCH(QString, eventType);
if (eventType == "MouseButton") {
QPoint textInputCenter = elementCenter(view, QStringLiteral("input2"));
- QTest::mouseClick(view->window(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view->window(), Qt::LeftButton, {}, textInputCenter);
} else if (eventType == "Touch") {
QPoint textInputCenter = elementCenter(view, QStringLiteral("input2"));
QTouchDevice *touchDevice = QTest::createTouchDevice();
@@ -618,7 +618,7 @@ void tst_QQuickWebEngineView::inputContextQueryInput()
// Set focus on an input field.
QPoint textInputCenter = elementCenter(view, "input1");
- QTest::mouseClick(view->window(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view->window(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(testContext.infos.count(), 2);
QCOMPARE(evaluateJavaScriptSync(view, "document.activeElement.id").toString(), QStringLiteral("input1"));
foreach (const InputMethodInfo &info, testContext.infos) {
@@ -1003,7 +1003,7 @@ void tst_QQuickWebEngineView::changeLocale()
QTRY_VERIFY(!evaluateJavaScriptSync(viewDE.data(), "document.body").isNull());
QTRY_VERIFY(!evaluateJavaScriptSync(viewDE.data(), "document.body.innerText").isNull());
- errorLines = evaluateJavaScriptSync(viewDE.data(), "document.body.innerText").toString().split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
+ errorLines = evaluateJavaScriptSync(viewDE.data(), "document.body.innerText").toString().split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("Die Website ist nicht erreichbar"));
QLocale::setDefault(QLocale("en"));
@@ -1013,7 +1013,7 @@ void tst_QQuickWebEngineView::changeLocale()
QTRY_VERIFY(!evaluateJavaScriptSync(viewEN.data(), "document.body").isNull());
QTRY_VERIFY(!evaluateJavaScriptSync(viewEN.data(), "document.body.innerText").isNull());
- errorLines = evaluateJavaScriptSync(viewEN.data(), "document.body.innerText").toString().split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
+ errorLines = evaluateJavaScriptSync(viewEN.data(), "document.body.innerText").toString().split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("This site can\xE2\x80\x99t be reached"));
// Reset error page
@@ -1026,7 +1026,7 @@ void tst_QQuickWebEngineView::changeLocale()
QTRY_VERIFY(!evaluateJavaScriptSync(viewDE.data(), "document.body").isNull());
QTRY_VERIFY(!evaluateJavaScriptSync(viewDE.data(), "document.body.innerText").isNull());
- errorLines = evaluateJavaScriptSync(viewDE.data(), "document.body.innerText").toString().split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
+ errorLines = evaluateJavaScriptSync(viewDE.data(), "document.body.innerText").toString().split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("Die Website ist nicht erreichbar"));
}
diff --git a/tests/auto/widgets/accessibility/tst_accessibility.cpp b/tests/auto/widgets/accessibility/tst_accessibility.cpp
index 117a9e573..9ec9e6a5b 100644
--- a/tests/auto/widgets/accessibility/tst_accessibility.cpp
+++ b/tests/auto/widgets/accessibility/tst_accessibility.cpp
@@ -333,138 +333,198 @@ void tst_Accessibility::value()
void tst_Accessibility::roles_data()
{
QTest::addColumn<QString>("html");
- QTest::addColumn<bool>("isSection");
+ QTest::addColumn<int>("nested");
QTest::addColumn<QAccessible::Role>("role");
- QTest::newRow("AX_ROLE_ABBR") << QString("<abbr>a</abbr>") << false << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_ALERT") << QString("<div role='alert'>alert</div>") << true << QAccessible::AlertMessage;
- QTest::newRow("AX_ROLE_ALERT_DIALOG") << QString("<div role='alertdialog'>alert</div>") << true << QAccessible::AlertMessage;
- //QTest::newRow("AX_ROLE_ANCHOR") << QString("<a>target</a>") << false << QAccessible::Link; // FIXME: The test case might be wrong (see https://codereview.chromium.org/2713193003)
- QTest::newRow("AX_ROLE_ANNOTATION") << QString("<rt>a</rt>") << false << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_APPLICATION") << QString("<div role='application'>landmark</div>") << true << QAccessible::Document;
- QTest::newRow("AX_ROLE_ARTICLE") << QString("<article>a</article>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_AUDIO") << QString("<audio controls><source src='test.mp3' type='audio/mpeg'></audio>") << false << QAccessible::Sound;
- QTest::newRow("AX_ROLE_BANNER") << QString("<header>a</header>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_BLOCKQUOTE") << QString("<blockquote>a</blockquote>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_BUTTON") << QString("<button>a</button>") << false << QAccessible::Button;
- //QTest::newRow("AX_ROLE_BUTTON_DROP_DOWN"); // TODO: Remove this during the next Chromium update: https://chromium-review.googlesource.com/842475
- //QTest::newRow("AX_ROLE_CANVAS") << QString("<canvas width='10' height='10'></canvas>") << true << QAccessible::Canvas; // FIXME: The test case might be wrong (see AXLayoutObject.cpp)
- QTest::newRow("AX_ROLE_CAPTION") << QString("<table><caption>a</caption></table>") << false << QAccessible::Heading;
- //QTest::newRow("AX_ROLE_CARET"); // Not a blink accessibility role
- //QTest::newRow("AX_ROLE_CELL") << QString("<td role='cell'>a</td>") << true << QAccessible::Cell; // FIXME: Aria role 'cell' should work for <td>
- QTest::newRow("AX_ROLE_CHECK_BOX") << QString("<input type='checkbox'>a</input>") << false << QAccessible::CheckBox;
- QTest::newRow("AX_ROLE_CLIENT") << QString("") << true << QAccessible::Client;
- QTest::newRow("AX_ROLE_COLOR_WELL") << QString("<input type='color'>a</input>") << false << QAccessible::ColorChooser;
- //QTest::newRow("AX_ROLE_COLUMN") << QString("<table><tr><td>a</td></tr>") << true << QAccessible::Column; // FIXME: The test case might be wrong (see AXTableColumn.h)
- QTest::newRow("AX_ROLE_COLUMN_HEADER") << QString("<div role='columnheader'>a</div>") << true << QAccessible::ColumnHeader;
- QTest::newRow("AX_ROLE_COMBO_BOX_GROUPING") << QString("<div role='combobox'><input></div>") << true << QAccessible::ComboBox;
- QTest::newRow("AX_ROLE_COMBO_BOX_MENU_BUTTON") << QString("<div tabindex=0 role='combobox'>Select</div>") << true << QAccessible::ComboBox;
- QTest::newRow("AX_ROLE_TEXT_FIELD_WITH_COMBO_BOX") << QString("<input role='combobox'>") << false << QAccessible::ComboBox;
- QTest::newRow("AX_ROLE_COMPLEMENTARY") << QString("<aside>a</aside>") << true << QAccessible::ComplementaryContent;
- QTest::newRow("AX_ROLE_CONTENT_INFO") << QString("<address>a</address>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_DATE") << QString("<input type='date'></input>") << false << QAccessible::Clock;
- QTest::newRow("AX_ROLE_DATE_TIME") << QString("<input type='datetime-local'></input>") << false << QAccessible::Clock;
- QTest::newRow("AX_ROLE_DEFINITION") << QString("<div role='definition'>landmark</div>") << true << QAccessible::Paragraph;
- QTest::newRow("AX_ROLE_DESCRIPTION_LIST") << QString("<dl>a</dl>") << true << QAccessible::List;
- QTest::newRow("AX_ROLE_DESCRIPTION_LIST_DETAIL") << QString("<dd>a</dd>") << true << QAccessible::Paragraph;
- QTest::newRow("AX_ROLE_DESCRIPTION_LIST_TERM") << QString("<dt>a</dt>") << true << QAccessible::ListItem;
- QTest::newRow("AX_ROLE_DETAILS") << QString("<details>a</details>") << true << QAccessible::Grouping;
- //QTest::newRow("AX_ROLE_DESKTOP"); // Not a blink accessibility role
- QTest::newRow("AX_ROLE_DIALOG") << QString("<div role='dialog'></div>") << true << QAccessible::Dialog;
- //QTest::newRow("AX_ROLE_DIRECTORY") << QString("<div role='directory'></div>") << true << QAccessible::NoRole; // FIXME: Aria role 'directory' should work
- QTest::newRow("AX_ROLE_DISCLOSURE_TRIANGLE") << QString("<details><summary>a</summary></details>") << false << QAccessible::NoRole;
- QTest::newRow("AX_ROLE_GENERIC_CONTAINER") << QString("<div>a</div>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_DOCUMENT") << QString("<div role='document'>a</div>") << true << QAccessible::Document;
- QTest::newRow("AX_ROLE_EMBEDDED_OBJECT") << QString("<object width='10' height='10'></object>") << false << QAccessible::Grouping;
- QTest::newRow("AX_ROLE_FEED") << QString("<div role='feed'>a</div>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_FIGCAPTION") << QString("<figcaption>a</figcaption>") << true << QAccessible::Heading;
- QTest::newRow("AX_ROLE_FIGURE") << QString("<figure>a</figure>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_FOOTER") << QString("<footer>a</footer>") << true << QAccessible::Footer;
- QTest::newRow("AX_ROLE_FORM") << QString("<form></form>") << true << QAccessible::Form;
- QTest::newRow("AX_ROLE_GRID") << QString("<div role='grid'></div>") << true << QAccessible::Table;
- QTest::newRow("AX_ROLE_GROUP") << QString("<fieldset></fieldset>") << true << QAccessible::Grouping;
- QTest::newRow("AX_ROLE_HEADING") << QString("<h1>a</h1>") << true << QAccessible::Heading;
- QTest::newRow("AX_ROLE_IFRAME") << QString("<iframe>a</iframe>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_IFRAME_PRESENTATIONAL") << QString("<iframe role='presentation'>a</iframe>") << false << QAccessible::NoRole;
- //QTest::newRow("AX_ROLE_IGNORED") << QString("<tag>a</tag>") << true << QAccessible::NoRole; // FIXME: The HTML element should not be exposed as an element (see AXNodeObject.cpp)
- QTest::newRow("AX_ROLE_IMAGE") << QString("<img>") << false << QAccessible::Graphic;
- //QTest::newRow("AX_ROLE_IMAGE_MAP") << QString("<map>a</map>") << true << QAccessible::Graphic; // FIXME: The test case might be wrong (see AXLayoutObject.cpp)
- QTest::newRow("AX_ROLE_INLINE_TEXT_BOX") << QString("<textarea rows='4' cols='50'></textarea>") << false << QAccessible::EditableText;
- QTest::newRow("AX_ROLE_INPUT_TIME") << QString("<input type='time'></input>") << false << QAccessible::SpinBox;
- QTest::newRow("AX_ROLE_LABEL_TEXT") << QString("<label>a</label>") << false << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_LEGEND") << QString("<legend>a</legend>") << true << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_LINE_BREAK") << QString("<br>") << false << QAccessible::Separator;
- QTest::newRow("AX_ROLE_LINK") << QString("<a href=''>link</a>") << false << QAccessible::Link;
- QTest::newRow("AX_ROLE_LIST") << QString("<ul></ul>") << true << QAccessible::List;
- QTest::newRow("AX_ROLE_LIST_BOX") << QString("<select multiple></select>") << false << QAccessible::ComboBox;
- QTest::newRow("AX_ROLE_LIST_BOX_OPTION") << QString("<option>a</option>") << true << QAccessible::ListItem;
- QTest::newRow("AX_ROLE_LIST_ITEM") << QString("<li>a</li>") << true << QAccessible::ListItem;
- QTest::newRow("AX_ROLE_LIST_MARKER") << QString("<li><ul></ul></li>") << false << QAccessible::StaticText;
- //QTest::newRow("AX_ROLE_LOCATION_BAR"); // Not a blink accessibility role
- QTest::newRow("AX_ROLE_LOG") << QString("<div role='log'>a</div>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_MAIN") << QString("<main>a</main>") << true << QAccessible::Grouping;
- QTest::newRow("AX_ROLE_MARK") << QString("<mark>a</mark>") << false << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_MARQUEE") << QString("<div role='marquee'>a</div>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_MATH") << QString("<math>a</math>") << false << QAccessible::Equation;
- QTest::newRow("AX_ROLE_MENU") << QString("<div role='menu'>a</div>") << true << QAccessible::PopupMenu;
- QTest::newRow("AX_ROLE_MENU_BAR") << QString("<div role='menubar'>a</div>") << true << QAccessible::MenuBar;
- QTest::newRow("AX_ROLE_MENU_ITEM") << QString("<menu role='menu'><input type='button' /></menu>") << false << QAccessible::MenuItem;
- QTest::newRow("AX_ROLE_MENU_ITEM_CHECK_BOX") << QString("<menu role='menu'><input type='checkbox'></input></menu>") << false << QAccessible::CheckBox;
- QTest::newRow("AX_ROLE_MENU_ITEM_RADIO") << QString("<menu role='menu'><input type='radio'></input></menu>") << false << QAccessible::RadioButton;
- QTest::newRow("AX_ROLE_MENU_BUTTON") << QString("<menu role='group'><div role='menuitem'>a</div></menu>") << false << QAccessible::MenuItem;
- //QTest::newRow("AX_ROLE_MENU_LIST_OPTION") << QString("<select role='menu'><option>a</option></select>") << false << QAccessible::MenuItem; // FIXME: <select> should be a menu list (see AXMenuListOption.cpp)
- //QTest::newRow("AX_ROLE_MENU_LIST_POPUP") << QString("<menu type='context'>a</menu>") << true << QAccessible::PopupMenu; // FIXME: <menu> is not fully supported by Chromium (see AXMenuListPopup.h)
- QTest::newRow("AX_ROLE_METER") << QString("<meter>a</meter>") << false << QAccessible::Chart;
- QTest::newRow("AX_ROLE_NAVIGATION") << QString("<nav>a</nav>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_NOTE") << QString("<div role='note'>a</div>") << true << QAccessible::Note;
- //QTest::newRow("AX_ROLE_PANE"); // Not a blink accessibility role
- QTest::newRow("AX_ROLE_PARAGRAH") << QString("<p>a</p>") << true << QAccessible::Paragraph;
- QTest::newRow("AX_ROLE_POP_UP_BUTTON") << QString("<select><option>a</option></select>") << false << QAccessible::ComboBox;
- QTest::newRow("AX_ROLE_PRE") << QString("<pre>a</pre>") << true << QAccessible::Section;
- //QTest::newRow("AX_ROLE_PRESENTATIONAL") << QString("<div role='presentation'>a</div>") << true << QAccessible::NoRole; // FIXME: Aria role 'presentation' should work
- QTest::newRow("AX_ROLE_PROGRESS_INDICATOR") << QString("<div role='progressbar' aria-valuenow='77' aria-valuemin='22' aria-valuemax='99'></div>") << true << QAccessible::ProgressBar;
- QTest::newRow("AX_ROLE_RADIO_BUTTON") << QString("<input type='radio'></input>") << false << QAccessible::RadioButton;
- QTest::newRow("AX_ROLE_RADIO_GROUP") << QString("<fieldset role='radiogroup'></fieldset>") << true << QAccessible::Grouping;
- QTest::newRow("AX_ROLE_REGION") << QString("<section>a</section>") << true << QAccessible::Section;
- //QTest::newRow("AX_ROLE_ROW") << QString("<tr role='row'>a</tr>") << true << QAccessible::Row; // FIXME: Aria role 'row' should work for <tr>
- //QTest::newRow("AX_ROLE_ROW_HEADER") << QString("<td role='rowheader'>a</td>") << true << QAccessible::RowHeader; // FIXME: Aria role 'rowheader' should work for <td>
- QTest::newRow("AX_ROLE_RUBY") << QString("<ruby>a</ruby>") << false << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_SCROLL_BAR") << QString("<div role='scrollbar'>a</a>") << true << QAccessible::ScrollBar;
- QTest::newRow("AX_ROLE_SEARCH") << QString("<div role='search'>landmark</div>") << true << QAccessible::Section;
- QTest::newRow("AX_ROLE_SEARCH_BOX") << QString("<input type='search'></input>") << false << QAccessible::EditableText;
- QTest::newRow("AX_ROLE_SLIDER") << QString("<input type='range'></input>") << false << QAccessible::Slider;
- //QTest::newRow("AX_ROLE_SLIDER_THUMB"); // No mapping to ARIA role
- QTest::newRow("AX_ROLE_SPIN_BUTTON") << QString("<input type='number'></input>") << false << QAccessible::SpinBox;
- //QTest::newRow("AX_ROLE_SPIN_BUTTON_PART"); // No mapping to ARIA role
- QTest::newRow("AX_ROLE_SPLITER") << QString("<hr>") << true << QAccessible::Splitter;
- QTest::newRow("AX_ROLE_STATIC_TEXT") << QString("a") << false << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_STATUS") << QString("<output>a</output>") << false << QAccessible::Indicator;
- QTest::newRow("AX_ROLE_SVG_ROOT") << QString("<svg width='10' height='10'></svg>") << false << QAccessible::Graphic;
- QTest::newRow("AX_ROLE_SWITCH") << QString("<button aria-checked='false'>a</button>") << false << QAccessible::Button;
- //QTest::newRow("AX_ROLE_TABLE") << QString("<table>a</table>") << true << QAccessible::Table; // FIXME: The test case might be wrong (see AXTable.cpp)
- //QTest::newRow("AX_ROLE_TABLE_HEADER_CONTAINER"); // No mapping to ARIA role
- QTest::newRow("AX_ROLE_TAB") << QString("<div role='tab'>a</div>") << true << QAccessible::PageTab;
- QTest::newRow("AX_ROLE_TAB_LIST") << QString("<div role='tablist'>a</div>") << true << QAccessible::PageTabList;
- QTest::newRow("AX_ROLE_TAB_PANEL") << QString("<div role='tabpanel'>a</div>") << true << QAccessible::Pane;
- QTest::newRow("AX_ROLE_TERM") << QString("<div role='term'>a</div>") << true << QAccessible::StaticText;
- QTest::newRow("AX_ROLE_TEXT_FIELD") << QString("<input type='text'></input>") << false << QAccessible::EditableText;
- QTest::newRow("AX_ROLE_TIME") << QString("<time>a</time>") << false << QAccessible::Clock;
- QTest::newRow("AX_ROLE_TIMER") << QString("<div role='timer'>a</div>") << true << QAccessible::Clock;
- //QTest::newRow("AX_ROLE_TITLE_BAR"); // Not a blink accessibility role
- QTest::newRow("AX_ROLE_TOGGLE_BUTTON") << QString("<button aria-pressed='false'>a</button>") << false << QAccessible::Button;
- QTest::newRow("AX_ROLE_TOOLBAR") << QString("<div role='toolbar'>a</div>") << true << QAccessible::ToolBar;
- QTest::newRow("AX_ROLE_TOOLTIP") << QString("<div role='tooltip'>a</div>") << true << QAccessible::ToolTip;
- QTest::newRow("AX_ROLE_TREE") << QString("<div role='tree'>a</div>") << true << QAccessible::Tree;
- QTest::newRow("AX_ROLE_TREE_GRID") << QString("<div role='treegrid'>a</div>") << true << QAccessible::Tree;
- QTest::newRow("AX_ROLE_TREE_ITEM") << QString("<div role='treeitem'>a</div>") << true << QAccessible::TreeItem;
- QTest::newRow("AX_ROLE_VIDEO") << QString("<video><source src='test.mp4' type='video/mp4'></video>") << false << QAccessible::Animation;
- //QTest::newRow("AX_ROLE_WINDOW"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kAbbr") << QString("<abbr>a</abbr>") << 1 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::KAlert") << QString("<div role='alert'>alert</div>") << 0 << QAccessible::AlertMessage;
+ QTest::newRow("ax::mojom::Role::kAlertDialog") << QString("<div role='alertdialog'>alert</div>") << 0 << QAccessible::AlertMessage;
+ QTest::newRow("ax::mojom::Role::kAnchor") << QString("<a id='a'>Chapter a</a>") << 1 << QAccessible::Link;
+
+ // REMINDER: annotation roles are removed from Chromium 80: https://chromium-review.googlesource.com/c/chromium/src/+/1907074
+ //QTest::newRow("ax::mojom::Role::kAnnotationAttribution") << QString("<div role='annotation-attribution'></div>") << 0 << QAccessible::Section; // FIXME: Aria role 'annotation-attribution' should work
+ //QTest::newRow("ax::mojom::Role::kAnnotationCommentary") << QString("<div role='annotation-commentary'></div>") << 0 << QAccessible::Section; // FIXME: Aria role 'annotation-commentary' should work
+ //QTest::newRow("ax::mojom::Role::kAnnotationPresence") << QString("<div role='annotation-presence'></div>") << 0 << QAccessible::Section; // FIXME: Aria role 'annotation-presence' should work
+ //QTest::newRow("ax::mojom::Role::kAnnotationRevision") << QString("<div role='annotation-revision'></div>") << 0 << QAccessible::Section; // FIXME: Aria role 'annotation-revision' should work
+ //QTest::newRow("ax::mojom::Role::kAnnotationSuggestion") << QString("<div role='annotation-suggestion'></div>") << 0 << QAccessible::Section; // FIXME: Aria role 'annotation-suggestion' should work
+
+ QTest::newRow("ax::mojom::Role::kApplication") << QString("<div role='application'>landmark</div>") << 0 << QAccessible::Document;
+ QTest::newRow("ax::mojom::Role::kArticle") << QString("<article>a</article>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kAudio") << QString("<audio controls><source src='test.mp3' type='audio/mpeg'></audio>") << 1 << QAccessible::Sound;
+ QTest::newRow("ax::mojom::Role::kBanner") << QString("<div role='banner'>a</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kBlockquote") << QString("<blockquote>a</blockquote>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kButton") << QString("<button>a</button>") << 1 << QAccessible::Button;
+ //QTest::newRow("ax::mojom::Role::kCanvas") << QString("<canvas width='10' height='10'></canvas>") << 0 << QAccessible::Canvas; // FIXME: The test case might be wrong (see AXLayoutObject.cpp)
+ QTest::newRow("ax::mojom::Role::kCaption") << QString("<table><caption>a</caption></table>") << 1 << QAccessible::Heading;
+ //QTest::newRow("ax::mojom::Role::kCaret"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kCell") << QString("<table role=table><tr><td>a</td></tr></table>") << 2 << QAccessible::Cell;
+ QTest::newRow("ax::mojom::Role::kCheckBox") << QString("<input type='checkbox'>a</input>") << 1 << QAccessible::CheckBox;
+ QTest::newRow("ax::mojom::Role::kClient") << QString("") << 0 << QAccessible::Client;
+ QTest::newRow("ax::mojom::Role::kColorWell") << QString("<input type='color'>a</input>") << 1 << QAccessible::ColorChooser;
+ //QTest::newRow("ax::mojom::Role::kColumn") << QString("<table><tr><td>a</td></tr></table>") << 0 << QAccessible::Column; // FIXME: The test case might be wrong (see AXTableColumn.h)
+ QTest::newRow("ax::mojom::Role::kColumnHeader") << QString("<table role=table><tr><th>a</th></tr><tr><td>a</td></tr></table>") << 2 << QAccessible::ColumnHeader;
+ QTest::newRow("ax::mojom::Role::kComboBoxGrouping") << QString("<div role='combobox'><input></div>") << 0 << QAccessible::ComboBox;
+ QTest::newRow("ax::mojom::Role::kComboBoxMenuButton") << QString("<div tabindex=0 role='combobox'>Select</div>") << 0 << QAccessible::ComboBox;
+ QTest::newRow("ax::mojom::Role::kTextFieldWithComboBox") << QString("<input role='combobox'>") << 1 << QAccessible::ComboBox;
+ QTest::newRow("ax::mojom::Role::kComplementary") << QString("<aside>a</aside>") << 0 << QAccessible::ComplementaryContent;
+ QTest::newRow("ax::mojom::Role::kContentDeletion") << QString("<div role='deletion'></div>") << 0 << QAccessible::Grouping;
+ QTest::newRow("ax::mojom::Role::kContentInsertion") << QString("<div role='insertion'></div>") << 0 << QAccessible::Grouping;
+ QTest::newRow("ax::mojom::Role::kContentInfo") << QString("<div role='contentinfo'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kData") << QString("<input type='date'></input>") << 1 << QAccessible::Clock;
+ QTest::newRow("ax::mojom::Role::kDateTime") << QString("<input type='datetime-local'></input>") << 1 << QAccessible::Clock;
+ QTest::newRow("ax::mojom::Role::kDefinition") << QString("<div role='definition'>landmark</div>") << 0 << QAccessible::Paragraph;
+ QTest::newRow("ax::mojom::Role::kDescriptionList") << QString("<dl>a</dl>") << 0 << QAccessible::List;
+ QTest::newRow("ax::mojom::Role::kDescriptionListDetail") << QString("<dd>a</dd>") << 0 << QAccessible::Paragraph;
+ QTest::newRow("ax::mojom::Role::kDescriptionListTerm") << QString("<dt>a</dt>") << 0 << QAccessible::ListItem;
+ QTest::newRow("ax::mojom::Role::kDetails") << QString("<details>a</details>") << 0 << QAccessible::Grouping;
+ //QTest::newRow("ax::mojom::Role::kDesktop"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kDialog") << QString("<div role='dialog'></div>") << 0 << QAccessible::Dialog;
+ //QTest::newRow("ax::mojom::Role::kDirectory") << QString("<ul role='directory'></ul>") << 0 << QAccessible::List; // FIXME: Aria role 'directory' should work
+ QTest::newRow("ax::mojom::Role::kDisclosureTriangle") << QString("<details><summary>a</summary></details>") << 1 << QAccessible::Button;
+ QTest::newRow("ax::mojom::Role::kGenericContainer") << QString("<div>a</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocCover") << QString("<div role='doc-cover'></div>") << 0 << QAccessible::Graphic;
+ QTest::newRow("ax::mojom::Role::kDocBackLink") << QString("<div role='doc-backlink'></div>") << 0 << QAccessible::Link;
+ QTest::newRow("ax::mojom::Role::kDocBiblioRef") << QString("<div role='doc-biblioref'></div>") << 0 << QAccessible::Link;
+ QTest::newRow("ax::mojom::Role::kDocGlossRef") << QString("<div role='doc-glossref'></div>") << 0 << QAccessible::Link;
+ QTest::newRow("ax::mojom::Role::kDocNoteRef") << QString("<div role='doc-noteref'></div>") << 0 << QAccessible::Link;
+ QTest::newRow("ax::mojom::Role::kDocBiblioEntry") << QString("<div role='doc-biblioentry'></div>") << 0 << QAccessible::ListItem;
+ QTest::newRow("ax::mojom::Role::kDocEndnote") << QString("<div role='doc-endnote'></div>") << 0 << QAccessible::ListItem;
+ QTest::newRow("ax::mojom::Role::kDocFootnote") << QString("<div role='doc-footnote'></div>") << 0 << QAccessible::ListItem;
+ QTest::newRow("ax::mojom::Role::kDocPageBreak") << QString("<div role='doc-pagebreak'></div>") << 0 << QAccessible::Separator;
+ QTest::newRow("ax::mojom::Role::kDocAbstract") << QString("<div role='doc-abstract'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocAcknowledgements") << QString("<div role='doc-acknowledgments'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocAfterword") << QString("<div role='doc-afterword'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocAppendix") << QString("<div role='doc-appendix'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocBibliography") << QString("<div role='doc-bibliography'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocChapter") << QString("<div role='doc-chapter'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocColophon") << QString("<div role='doc-colophon'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocConclusion") << QString("<div role='doc-conclusion'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocCredit") << QString("<div role='doc-credit'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocCredits") << QString("<div role='doc-credits'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocDedication") << QString("<div role='doc-dedication'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocEndnotes") << QString("<div role='doc-endnotes'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocEpigraph") << QString("<div role='doc-epigraph'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocEpilogue") << QString("<div role='doc-epilogue'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocErrata") << QString("<div role='doc-errata'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocExample") << QString("<div role='doc-example'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocForeword") << QString("<div role='doc-foreword'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocGlossary") << QString("<div role='doc-glossary'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocIndex") << QString("<div role='doc-index'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocIntroduction") << QString("<div role='doc-introduction'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocNotice") << QString("<div role='doc-notice'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocPageList") << QString("<div role='doc-pagelist'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocPart") << QString("<div role='doc-part'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocPreface") << QString("<div role='doc-preface'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocPrologue") << QString("<div role='doc-prologue'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocPullquote") << QString("<div role='doc-pullquote'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocQna") << QString("<div role='doc-qna'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocSubtitle") << QString("<div role='doc-subtitle'></div>") << 0 << QAccessible::Heading;
+ QTest::newRow("ax::mojom::Role::kDocTip") << QString("<div role='doc-tip'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocToc") << QString("<div role='doc-toc'></div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kDocument") << QString("<div role='document'>a</div>") << 0 << QAccessible::Document;
+ QTest::newRow("ax::mojom::Role::kEmbeddedObject") << QString("<object width='10' height='10'></object>") << 1 << QAccessible::Grouping;
+ QTest::newRow("ax::mojom::Role::kFeed") << QString("<div role='feed'>a</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kFigcaption") << QString("<figcaption>a</figcaption>") << 0 << QAccessible::Heading;
+ QTest::newRow("ax::mojom::Role::kFigure") << QString("<figure>a</figure>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kFooter") << QString("<footer>a</footer>") << 0 << QAccessible::Footer;
+ QTest::newRow("ax::mojom::Role::kFooterAsNonLandmark") << QString("<article><footer>a</footer><article>") << 1 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kForm") << QString("<form></form>") << 0 << QAccessible::Form;
+ QTest::newRow("ax::mojom::Role::kGraphicsDocument") << QString("<div role='graphics-document'></div>") << 0 << QAccessible::Document;
+ QTest::newRow("ax::mojom::Role::kGraphicsObject") << QString("<div role='graphics-object'></div>") << 0 << QAccessible::Pane;
+ QTest::newRow("ax::mojom::Role::kGraphicsSymbol") << QString("<div role='graphics-symbol'></div>") << 0 << QAccessible::Graphic;
+ QTest::newRow("ax::mojom::Role::kGrid") << QString("<div role='grid'></div>") << 0 << QAccessible::Table;
+ QTest::newRow("ax::mojom::Role::kGroup") << QString("<fieldset></fieldset>") << 0 << QAccessible::Grouping;
+ QTest::newRow("ax::mojom::Role::Header") << QString("<header>a</header>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::HeaderAsNonLandMark") << QString("<article><header>a</header><article>") << 1 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kHeading") << QString("<h1>a</h1>") << 0 << QAccessible::Heading;
+ QTest::newRow("ax::mojom::Role::kIframe") << QString("<iframe>a</iframe>") << 1 << QAccessible::WebDocument;
+ QTest::newRow("ax::mojom::Role::kIframePresentational") << QString("<iframe role='presentation'>a</iframe>") << 1 << QAccessible::Grouping;
+ //QTest::newRow("ax::mojom::Role::kIgnored") << QString("<tag>a</tag>") << 0 << QAccessible::NoRole; // FIXME: The HTML element should not be exposed as an element (see AXNodeObject.cpp)
+ QTest::newRow("ax::mojom::Role::kImage") << QString("<img>") << 1 << QAccessible::Graphic;
+ //QTest::newRow("ax::mojom::Role::kImageMap") << QString("<img usemap='map'>") << 0 << QAccessible::Document; // FIXME: AXLayoutObject::DetermineAccessiblityRole returns kImageMap but something overrides it
+ //QTest::newRow("ax::mojom::Role::kInlineTextBox"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kInputTime") << QString("<input type='time'></input>") << 1 << QAccessible::SpinBox;
+ //QTest::newRow("ax::mojom::Role::kKeyboard"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kLabelText") << QString("<label>a</label>") << 1 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kLayoutTable") << QString("<table><tr><td></td></tr></table>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kLayoutTableCell") << QString("<table><tr><td></td></tr></table>") << 2 << QAccessible::Section;
+ //QTest::newRow("ax::mojom::Role::kLayoutTableColumn") << QString("<table><tr></tr></table>") << 1 << QAccessible::Section; // FIXME: The test case might be wrong
+ QTest::newRow("ax::mojom::Role::kLayoutTableRow") << QString("<table><tr><td></td></tr></table>") << 1 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kLegend") << QString("<legend>a</legend>") << 0 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kLineBreak") << QString("<br>") << 1 << QAccessible::Separator;
+ QTest::newRow("ax::mojom::Role::kLink") << QString("<a href=''>link</a>") << 1 << QAccessible::Link;
+ QTest::newRow("ax::mojom::Role::kList") << QString("<ul></ul>") << 0 << QAccessible::List;
+ QTest::newRow("ax::mojom::Role::kListBox") << QString("<select multiple></select>") << 1 << QAccessible::ComboBox;
+ QTest::newRow("ax::mojom::Role::kListBoxOption") << QString("<option>a</option>") << 0 << QAccessible::ListItem;
+ QTest::newRow("ax::mojom::Role::kListItem") << QString("<li>a</li>") << 0 << QAccessible::ListItem;
+ //QTest::newRow("ax::mojom::Role::kListGrid"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kListMarker") << QString("<li><ul></ul></li>") << 1 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kLog") << QString("<div role='log'>a</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kMain") << QString("<main>a</main>") << 0 << QAccessible::Grouping;
+ QTest::newRow("ax::mojom::Role::kMark") << QString("<mark>a</mark>") << 1 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kMarquee") << QString("<div role='marquee'>a</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kMath") << QString("<math>a</math>") << 1 << QAccessible::Equation;
+ QTest::newRow("ax::mojom::Role::kMenu") << QString("<div role='menu'>a</div>") << 0 << QAccessible::PopupMenu;
+ QTest::newRow("ax::mojom::Role::kMenuBar") << QString("<div role='menubar'>a</div>") << 0 << QAccessible::MenuBar;
+ QTest::newRow("ax::mojom::Role::kMenuItem") << QString("<menu role='menu'><input type='button' /></menu>") << 1 << QAccessible::MenuItem;
+ QTest::newRow("ax::mojom::Role::kMenuItemCheckBox") << QString("<menu role='menu'><input type='checkbox'></input></menu>") << 1 << QAccessible::CheckBox;
+ QTest::newRow("ax::mojom::Role::kMenuItemRadio") << QString("<menu role='menu'><input type='radio'></input></menu>") << 1 << QAccessible::RadioButton;
+ QTest::newRow("ax::mojom::Role::kMenuButton") << QString("<menu role='group'><div role='menuitem'>a</div></menu>") << 1 << QAccessible::MenuItem;
+ QTest::newRow("ax::mojom::Role::kMenuListOption") << QString("<select role='menu'><option>a</option></select>") << 3 << QAccessible::MenuItem;
+ QTest::newRow("ax::mojom::Role::kMenuListPopup") << QString("<select role='menu'><option>a</option></select>") << 2 << QAccessible::PopupMenu;
+ QTest::newRow("ax::mojom::Role::kMeter") << QString("<meter>a</meter>") << 1 << QAccessible::Chart;
+ QTest::newRow("ax::mojom::Role::kNavigation") << QString("<nav>a</nav>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kNote") << QString("<div role='note'>a</div>") << 0 << QAccessible::Note;
+ //QTest::newRow("ax::mojom::Role::kPane"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kParagraph") << QString("<p>a</p>") << 0 << QAccessible::Paragraph;
+ QTest::newRow("ax::mojom::Role::kPopUpButton") << QString("<select><option>a</option></select>") << 1 << QAccessible::ComboBox;
+ QTest::newRow("ax::mojom::Role::kPre") << QString("<pre>a</pre>") << 0 << QAccessible::Section;
+ //QTest::newRow("ax::mojom::Role::kPresentational") << QString("<div role='presentation'>a</div>") << 0 << QAccessible::NoRole; // FIXME: Aria role 'presentation' should work
+ QTest::newRow("ax::mojom::Role::kProgressIndicator") << QString("<div role='progressbar' aria-valuenow='77' aria-valuemin='22' aria-valuemax='99'></div>") << 0 << QAccessible::ProgressBar;
+ QTest::newRow("ax::mojom::Role::kRadioButton") << QString("<input type='radio'></input>") << 1 << QAccessible::RadioButton;
+ QTest::newRow("ax::mojom::Role::kRadioGroup") << QString("<fieldset role='radiogroup'></fieldset>") << 0 << QAccessible::Grouping;
+ QTest::newRow("ax::mojom::Role::kRegion") << QString("<div role='region'>a</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kRow") << QString("<table role=table><tr><td>a</td></tr></table>") << 1 << QAccessible::Row;
+ QTest::newRow("ax::mojom::Role::kRowHeader") << QString("<table role=table><tr><th>a</td><td>b</td></tr></table>") << 2 << QAccessible::RowHeader;
+ QTest::newRow("ax::mojom::Role::kRuby") << QString("<ruby>a</ruby>") << 1 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kRubyAnnotation") << QString("<ruby><rt>a</rt></ruby>") << 2 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kScrollBar") << QString("<div role='scrollbar'>a</a>") << 0 << QAccessible::ScrollBar;
+ //QTest::newRow("ax::mojom::Role::kScrollView"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kSearch") << QString("<div role='search'>landmark</div>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kSearchBox") << QString("<input type='search'></input>") << 1 << QAccessible::EditableText;
+ QTest::newRow("ax::mojom::Role::kSection") << QString("<section></section>") << 0 << QAccessible::Section;
+ QTest::newRow("ax::mojom::Role::kSlider") << QString("<input type='range'>") << 1 << QAccessible::Slider;
+ //QTest::newRow("ax::mojom::Role::kSliderThumb") << QString("<input type='range'>") << 1 << QAccessible::Slider; // TODO: blink/renderer/modules/accessibility/ax_slider.cc
+ QTest::newRow("ax::mojom::Role::kSpinButton") << QString("<input type='number'></input>") << 1 << QAccessible::SpinBox;
+ QTest::newRow("ax::mojom::Role::kSplitter") << QString("<hr>") << 0 << QAccessible::Splitter;
+ QTest::newRow("ax::mojom::Role::kStaticText") << QString("a") << 1 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kStatus") << QString("<output>a</output>") << 1 << QAccessible::Indicator;
+ QTest::newRow("ax::mojom::Role::kSvgRoot") << QString("<svg width='10' height='10'></svg>") << 1 << QAccessible::Graphic;
+ QTest::newRow("ax::mojom::Role::kSwitch") << QString("<button aria-checked='false'>a</button>") << 1 << QAccessible::Button;
+ QTest::newRow("ax::mojom::Role::kTable") << QString("<table role=table><td>a</td></table>") << 0 << QAccessible::Table;
+ //QTest::newRow("ax::mojom::Role::kTableHeaderContainer"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kTab") << QString("<div role='tab'>a</div>") << 0 << QAccessible::PageTab;
+ QTest::newRow("ax::mojom::Role::kTabList") << QString("<div role='tablist'>a</div>") << 0 << QAccessible::PageTabList;
+ QTest::newRow("ax::mojom::Role::kTabPanel") << QString("<div role='tabpanel'>a</div>") << 0 << QAccessible::Pane;
+ QTest::newRow("ax::mojom::Role::kTerm") << QString("<div role='term'>a</div>") << 0 << QAccessible::StaticText;
+ QTest::newRow("ax::mojom::Role::kTextField") << QString("<input type='text'></input>") << 1 << QAccessible::EditableText;
+ QTest::newRow("ax::mojom::Role::kTime") << QString("<time>a</time>") << 1 << QAccessible::Clock;
+ QTest::newRow("ax::mojom::Role::kTimer") << QString("<div role='timer'>a</div>") << 0 << QAccessible::Clock;
+ //QTest::newRow("ax::mojom::Role::kTitleBar"); // No mapping to ARIA role
+ QTest::newRow("ax::mojom::Role::kToggleButton") << QString("<button aria-pressed='false'>a</button>") << 1 << QAccessible::Button;
+ QTest::newRow("ax::mojom::Role::kToolbar") << QString("<div role='toolbar'>a</div>") << 0 << QAccessible::ToolBar;
+ QTest::newRow("ax::mojom::Role::kToolTip") << QString("<div role='tooltip'>a</div>") << 0 << QAccessible::ToolTip;
+ QTest::newRow("ax::mojom::Role::kTree") << QString("<div role='tree'>a</div>") << 0 << QAccessible::Tree;
+ QTest::newRow("ax::mojom::Role::kTreeGrid") << QString("<div role='treegrid'>a</div>") << 0 << QAccessible::Tree;
+ QTest::newRow("ax::mojom::Role::kTreeItem") << QString("<div role='treeitem'>a</div>") << 0 << QAccessible::TreeItem;
+ QTest::newRow("ax::mojom::Role::kVideo") << QString("<video><source src='test.mp4' type='video/mp4'></video>") << 1 << QAccessible::Animation;
+ //QTest::newRow("ax::mojom::Role::kWindow"); // No mapping to ARIA role
}
void tst_Accessibility::roles()
{
QFETCH(QString, html);
- QFETCH(bool, isSection);
+ QFETCH(int, nested);
QFETCH(QAccessible::Role, role);
QWebEngineView webView;
@@ -483,15 +543,13 @@ void tst_Accessibility::roles()
QTRY_COMPARE(view->child(0)->childCount(), 1);
QAccessibleInterface *document = view->child(0);
- QAccessibleInterface *section = document->child(0);
+ QAccessibleInterface *element = document->child(0);
- if (isSection) {
- QCOMPARE(section->role(), role);
- return;
+ while (nested--) {
+ QTRY_VERIFY(element->child(0));
+ element = element->child(0);
}
- QVERIFY(section->childCount() > 0);
- QAccessibleInterface *element = section->child(0);
QCOMPARE(element->role(), role);
}
diff --git a/tests/auto/widgets/origins/tst_origins.cpp b/tests/auto/widgets/origins/tst_origins.cpp
index c63f4d690..e3927f763 100644
--- a/tests/auto/widgets/origins/tst_origins.cpp
+++ b/tests/auto/widgets/origins/tst_origins.cpp
@@ -481,6 +481,8 @@ void tst_Origins::subdirWithoutAccess()
{
ScopedAttribute sa(m_page->settings(), QWebEngineSettings::LocalContentCanAccessFileUrls, false);
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/subdir/index.html")));
QCOMPARE(eval(QSL("msg[0]")), QVariant());
QCOMPARE(eval(QSL("msg[1]")), QVariant());
@@ -507,22 +509,28 @@ void tst_Origins::mixedSchemes()
QVERIFY(verifyLoad(QSL("file:" THIS_DIR "resources/mixedSchemes.html")));
eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
QVERIFY(verifyLoad(QSL("qrc:/resources/mixedSchemes.html")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
QVERIFY(verifyLoad(QSL("tst:/resources/mixedSchemes.html")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource")));
eval(QSL("setIFrameUrl('file:" THIS_DIR "resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('qrc:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
eval(QSL("setIFrameUrl('tst:/resources/mixedSchemes_frame.html')"));
@@ -531,36 +539,47 @@ void tst_Origins::mixedSchemes()
QVERIFY(verifyLoad(QSL("PathSyntax:/resources/mixedSchemes.html")));
eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource")));
eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad")));
eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')"));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
QVERIFY(verifyLoad(QSL("PathSyntax-LocalAccessAllowed:/resources/mixedSchemes.html")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
QVERIFY(verifyLoad(QSL("PathSyntax-NoAccessAllowed:/resources/mixedSchemes.html")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Not allowed to load local resource")));
eval(QSL("setIFrameUrl('PathSyntax-Local:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("cannotLoad")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax-LocalAccessAllowed:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('PathSyntax-NoAccessAllowed:/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
QVERIFY(verifyLoad(QSL("HostSyntax://a/resources/mixedSchemes.html")));
eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
}
@@ -569,14 +588,17 @@ void tst_Origins::mixedSchemes()
void tst_Origins::mixedSchemesWithCsp()
{
QVERIFY(verifyLoad(QSL("HostSyntax://a/resources/mixedSchemesWithCsp.html")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("violates the following Content Security Policy")));
eval(QSL("setIFrameUrl('HostSyntax://a/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("violates the following Content Security Policy")));
eval(QSL("setIFrameUrl('HostSyntax://b/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
QVERIFY(verifyLoad(QSL("HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemesWithCsp.html")));
eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://a/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadAndAccess")));
+ QTest::ignoreMessage(QtSystemMsg, QRegularExpression(QSL("Uncaught SecurityError")));
eval(QSL("setIFrameUrl('HostSyntax-ContentSecurityPolicyIgnored://b/resources/mixedSchemes_frame.html')"));
QTRY_COMPARE(eval(QSL("result")), QVariant(QSL("canLoadButNotAccess")));
}
diff --git a/tests/auto/widgets/proxypac/proxypac.pri b/tests/auto/widgets/proxypac/proxypac.pri
new file mode 100644
index 000000000..b3b2856c8
--- /dev/null
+++ b/tests/auto/widgets/proxypac/proxypac.pri
@@ -0,0 +1,5 @@
+TEMPLATE = app
+CONFIG += testcase
+QT += testlib network webenginewidgets webengine
+HEADERS += $$PWD/proxyserver.h
+SOURCES += $$PWD/proxyserver.cpp $$PWD/tst_proxypac.cpp
diff --git a/tests/auto/widgets/proxypac/proxypac.pro b/tests/auto/widgets/proxypac/proxypac.pro
index 4dbcd9365..f2a43d41f 100644
--- a/tests/auto/widgets/proxypac/proxypac.pro
+++ b/tests/auto/widgets/proxypac/proxypac.pro
@@ -1,11 +1,4 @@
-include(../tests.pri)
-QT += webengine
-HEADERS += proxyserver.h
-SOURCES += proxyserver.cpp
-
-proxy_pac.name = QTWEBENGINE_CHROMIUM_FLAGS
-boot2qt:proxy_pac.value = "--single-process --no-sandbox --proxy-pac-url=file://$$PWD/proxy.pac"
-else: proxy_pac.value = --proxy-pac-url="file://$$PWD/proxy.pac"
-
-QT_TOOL_ENV += proxy_pac
+TEMPLATE = subdirs
+SUBDIRS = proxypac_file proxypac_qrc
+CONFIG += ordered
diff --git a/tests/auto/widgets/proxypac/proxypac.qrc b/tests/auto/widgets/proxypac/proxypac.qrc
new file mode 100644
index 000000000..9047585a0
--- /dev/null
+++ b/tests/auto/widgets/proxypac/proxypac.qrc
@@ -0,0 +1,7 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+<qresource profix="/">
+ <file>proxy.pac</file>
+</qresource>
+</RCC>
+
diff --git a/tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro b/tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro
new file mode 100644
index 000000000..037123054
--- /dev/null
+++ b/tests/auto/widgets/proxypac/proxypac_file/proxypac_file.pro
@@ -0,0 +1,9 @@
+include(../proxypac.pri)
+
+proxy_pac.name = QTWEBENGINE_CHROMIUM_FLAGS
+win32:proxy_pac.value = --proxy-pac-url="file:///$$PWD/../proxy.pac"
+else:proxy_pac.value = --proxy-pac-url="file://$$PWD/../proxy.pac"
+boot2qt:proxy_pac.value = "--single-process --no-sandbox --proxy-pac-url=file://$$PWD/../proxy.pac"
+
+QT_TOOL_ENV += proxy_pac
+
diff --git a/tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro b/tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro
new file mode 100644
index 000000000..a5ab64605
--- /dev/null
+++ b/tests/auto/widgets/proxypac/proxypac_qrc/proxypac_qrc.pro
@@ -0,0 +1,7 @@
+include(../proxypac.pri)
+
+proxy_pac.name = QTWEBENGINE_CHROMIUM_FLAGS
+proxy_pac.value = --proxy-pac-url="qrc:///proxy.pac"
+boot2qt:proxy_pac.value = "--single-process --no-sandbox --proxy-pac-url=qrc:///proxy.pac"
+QT_TOOL_ENV += proxy_pac
+RESOURCES+= $$PWD/../proxypac.qrc
diff --git a/tests/auto/widgets/qwebenginepage/BLACKLIST b/tests/auto/widgets/qwebenginepage/BLACKLIST
index 2498ed765..02b297d5a 100644
--- a/tests/auto/widgets/qwebenginepage/BLACKLIST
+++ b/tests/auto/widgets/qwebenginepage/BLACKLIST
@@ -4,3 +4,9 @@ osx
[mouseMovementProperties]
windows
macos # Can't move cursor (QTBUG-76312)
+
+[devTools]
+msvc-2019
+
+[setLifecycleStateWithDevTools]
+msvc-2019
diff --git a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
index 94ce92e40..4945f6c91 100644
--- a/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
+++ b/tests/auto/widgets/qwebenginepage/tst_qwebenginepage.cpp
@@ -226,6 +226,7 @@ private Q_SLOTS:
void customUserAgentInNewTab();
void renderProcessCrashed();
+ void renderProcessPid();
void backgroundColor();
private:
@@ -799,7 +800,7 @@ void tst_QWebEnginePage::backActionUpdate()
};
QVERIFY(evaluateJavaScriptSync(page, "document.getElementsByName('frame_b')[0].contentDocument == undefined").toBool());
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, firstAnchorCenterInFrame(page, "frame_c"));
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, firstAnchorCenterInFrame(page, "frame_c"));
QTRY_VERIFY(evaluateJavaScriptSync(page, "document.getElementsByName('frame_b')[0].contentDocument != undefined").toBool());
QTRY_VERIFY(action->isEnabled());
}
@@ -983,7 +984,7 @@ void tst_QWebEnginePage::findText()
{
CallbackSpy<bool> callbackSpy;
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
- m_view->findText("", 0, callbackSpy.ref());
+ m_view->findText("", {}, callbackSpy.ref());
QVERIFY(callbackSpy.wasCalled());
QCOMPARE(signalSpy.count(), 1);
QTRY_COMPARE(m_view->selectedText(), QString("foo bar"));
@@ -994,7 +995,7 @@ void tst_QWebEnginePage::findText()
{
CallbackSpy<bool> callbackSpy;
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
- m_view->findText("Will not be found", 0, callbackSpy.ref());
+ m_view->findText("Will not be found", {}, callbackSpy.ref());
QCOMPARE(callbackSpy.waitForResult(), false);
QTRY_COMPARE(signalSpy.count(), 1);
auto result = signalSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
@@ -1011,7 +1012,7 @@ void tst_QWebEnginePage::findText()
{
CallbackSpy<bool> callbackSpy;
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
- m_view->findText("foo", 0, callbackSpy.ref());
+ m_view->findText("foo", {}, callbackSpy.ref());
QVERIFY(callbackSpy.waitForResult());
QTRY_COMPARE(signalSpy.count(), 1);
QTRY_VERIFY(m_view->selectedText().isEmpty());
@@ -1022,7 +1023,7 @@ void tst_QWebEnginePage::findText()
{
CallbackSpy<bool> callbackSpy;
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
- m_view->findText("", 0, callbackSpy.ref());
+ m_view->findText("", {}, callbackSpy.ref());
QTRY_VERIFY(callbackSpy.wasCalled());
QTRY_COMPARE(signalSpy.count(), 1);
QTRY_COMPARE(m_view->selectedText(), QString("foo"));
@@ -1032,8 +1033,8 @@ void tst_QWebEnginePage::findText()
// should interrupt the first one.
{
QSignalSpy signalSpy(m_view->page(), &QWebEnginePage::findTextFinished);
- m_view->findText("foo", 0);
- m_view->findText("foo", 0);
+ m_view->findText("foo", {});
+ m_view->findText("foo", {});
QTRY_COMPARE(signalSpy.count(), 2);
QTRY_VERIFY(m_view->selectedText().isEmpty());
@@ -1088,11 +1089,11 @@ void tst_QWebEnginePage::findTextSuccessiveShouldCallAllCallbacks()
QSignalSpy loadSpy(m_view, SIGNAL(loadFinished(bool)));
m_view->setHtml(QString("<html><head></head><body><div>abcdefg abcdefg abcdefg abcdefg abcdefg</div></body></html>"));
QTRY_COMPARE_WITH_TIMEOUT(loadSpy.count(), 1, 20000);
- m_page->findText("abcde", 0, spy1.ref());
- m_page->findText("abcd", 0, spy2.ref());
- m_page->findText("abc", 0, spy3.ref());
- m_page->findText("ab", 0, spy4.ref());
- m_page->findText("a", 0, spy5.ref());
+ m_page->findText("abcde", {}, spy1.ref());
+ m_page->findText("abcd", {}, spy2.ref());
+ m_page->findText("abc", {}, spy3.ref());
+ m_page->findText("ab", {}, spy4.ref());
+ m_page->findText("a", {}, spy5.ref());
spy5.waitForResult();
QVERIFY(spy1.wasCalled());
QVERIFY(spy2.wasCalled());
@@ -1113,10 +1114,10 @@ void tst_QWebEnginePage::findTextCalledOnMatch()
// CALLBACK
bool callbackCalled = false;
- m_view->page()->findText("foo", 0, [this, &callbackCalled](bool found) {
+ m_view->page()->findText("foo", {}, [this, &callbackCalled](bool found) {
QVERIFY(found);
- m_view->page()->findText("bar", 0, [&callbackCalled](bool found) {
+ m_view->page()->findText("bar", {}, [&callbackCalled](bool found) {
QVERIFY(found);
callbackCalled = true;
});
@@ -1150,7 +1151,7 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal()
// Iterate over all "foo" matches.
for (int i = 1; i <= 3; ++i) {
- m_view->page()->findText("foo", 0);
+ m_view->page()->findText("foo", {});
QTRY_COMPARE(findTextSpy.count(), 1);
result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
QCOMPARE(result.numberOfMatches(), 3);
@@ -1158,7 +1159,7 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal()
}
// The last match is followed by the fist one.
- m_view->page()->findText("foo", 0);
+ m_view->page()->findText("foo", {});
QTRY_COMPARE(findTextSpy.count(), 1);
result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
QCOMPARE(result.numberOfMatches(), 3);
@@ -1172,14 +1173,14 @@ void tst_QWebEnginePage::findTextActiveMatchOrdinal()
QCOMPARE(result.activeMatch(), 3);
// Finding another word resets the activeMatch.
- m_view->page()->findText("bar", 0);
+ m_view->page()->findText("bar", {});
QTRY_COMPARE(findTextSpy.count(), 1);
result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
QCOMPARE(result.numberOfMatches(), 2);
QCOMPARE(result.activeMatch(), 1);
// If no match activeMatch is 0.
- m_view->page()->findText("bla", 0);
+ m_view->page()->findText("bla", {});
QTRY_COMPARE(findTextSpy.count(), 1);
result = findTextSpy.takeFirst().value(0).value<QWebEngineFindTextResult>();
QCOMPARE(result.numberOfMatches(), 0);
@@ -1966,8 +1967,7 @@ void tst_QWebEnginePage::urlChange()
QUrl testUrl("http://test.qt.io/");
m_view->setHtml(QStringLiteral("<h1>Test</h1"), testUrl);
- QTRY_COMPARE(urlSpy.size(), 2);
- QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), QUrl("data:text/html;charset=UTF-8,%3Ch1%3ETest%3C%2Fh1"));
+ QTRY_COMPARE(urlSpy.size(), 1);
QCOMPARE(urlSpy.takeFirst().value(0).toUrl(), testUrl);
}
@@ -2079,7 +2079,7 @@ void tst_QWebEnginePage::requestedUrlAfterSetAndLoadFailures()
page.load(second);
QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 2, 20000);
- QCOMPARE(page.url(), second);
+ QCOMPARE(page.url(), first);
QCOMPARE(page.requestedUrl(), second);
QVERIFY(!spy.at(1).first().toBool());
}
@@ -2779,8 +2779,8 @@ void tst_QWebEnginePage::setUrlThenLoads()
QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1));
m_page->load(urlToLoad2);
- QTRY_COMPARE(m_page->url(), urlToLoad2);
- QTRY_COMPARE(m_page->requestedUrl(), urlToLoad2);
+ QCOMPARE(m_page->url(), urlToLoad1);
+ QCOMPARE(m_page->requestedUrl(), urlToLoad2);
QCOMPARE(baseUrlSync(m_page), extractBaseUrl(urlToLoad1));
QTRY_COMPARE(startedSpy.count(), 3);
@@ -3293,7 +3293,7 @@ void tst_QWebEnginePage::dataURLFragment()
QTRY_COMPARE(loadFinishedSpy.count(), 1);
QSignalSpy urlChangedSpy(m_page, SIGNAL(urlChanged(QUrl)));
- QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, 0, elementCenter(m_page, "link"));
+ QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link"));
QVERIFY(urlChangedSpy.wait());
QCOMPARE(m_page->url().fragment(), QStringLiteral("anchor"));
@@ -3303,7 +3303,7 @@ void tst_QWebEnginePage::dataURLFragment()
"</body></html>", QUrl("http://test.qt.io/mytest.html"));
QTRY_COMPARE(loadFinishedSpy.count(), 2);
- QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, 0, elementCenter(m_page, "link"));
+ QTest::mouseClick(m_view->focusProxy(), Qt::LeftButton, {}, elementCenter(m_page, "link"));
QVERIFY(urlChangedSpy.wait());
QCOMPARE(m_page->url(), QUrl("http://test.qt.io/mytest.html#anchor"));
}
@@ -3325,7 +3325,7 @@ void tst_QWebEnginePage::devTools()
QCOMPARE(devToolsPage.devToolsPage(), nullptr);
QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage1);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000);
QVERIFY(spy.takeFirst().value(0).toBool());
devToolsPage.setInspectedPage(&inspectedPage2);
@@ -3337,7 +3337,7 @@ void tst_QWebEnginePage::devTools()
QCOMPARE(devToolsPage.devToolsPage(), nullptr);
QCOMPARE(devToolsPage.inspectedPage(), &inspectedPage2);
- QTRY_COMPARE(spy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(spy.count(), 1, 30000);
QVERIFY(spy.takeFirst().value(0).toBool());
devToolsPage.setInspectedPage(nullptr);
@@ -3373,7 +3373,7 @@ void tst_QWebEnginePage::openLinkInDifferentProfile()
QTRY_COMPARE(spy1.count(), 1);
QVERIFY(spy1.takeFirst().value(0).toBool());
page1.targetPage = &page2;
- QTest::mouseClick(view.focusProxy(), Qt::MiddleButton, 0, elementCenter(&page1, "link"));
+ QTest::mouseClick(view.focusProxy(), Qt::MiddleButton, {}, elementCenter(&page1, "link"));
QTRY_COMPARE(spy2.count(), 1);
QVERIFY(spy2.takeFirst().value(0).toBool());
}
@@ -3817,9 +3817,9 @@ void tst_QWebEnginePage::setLifecycleStateWithDevTools()
// Ensure pages are initialized
inspectedPage.load(QStringLiteral("about:blank"));
devToolsPage.load(QStringLiteral("about:blank"));
- QTRY_COMPARE(inspectedSpy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(inspectedSpy.count(), 1, 30000);
QCOMPARE(inspectedSpy.takeFirst().value(0), QVariant(true));
- QTRY_COMPARE(devToolsSpy.count(), 1);
+ QTRY_COMPARE_WITH_TIMEOUT(devToolsSpy.count(), 1, 30000);
QCOMPARE(devToolsSpy.takeFirst().value(0), QVariant(true));
// Open DevTools with Frozen inspectedPage
@@ -4330,7 +4330,7 @@ void tst_QWebEnginePage::customUserAgentInNewTab()
QTRY_COMPARE(spy.count(), 1);
QVERIFY(spy.takeFirst().value(0).toBool());
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("navigator.userAgent")).toString(), profile1.httpUserAgent());
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, elementCenter(&page, "link"));
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link"));
QTRY_VERIFY(page.newPage);
QTRY_VERIFY(!lastUserAgent.isEmpty());
QCOMPARE(lastUserAgent, profile1.httpUserAgent().toUtf8());
@@ -4345,7 +4345,7 @@ void tst_QWebEnginePage::customUserAgentInNewTab()
QString("'>link</a></body></html>"));
QTRY_COMPARE(spy.count(), 1);
QVERIFY(spy.takeFirst().value(0).toBool());
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, elementCenter(&page, "link"));
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, elementCenter(&page, "link"));
QTRY_VERIFY(page.newPage);
QTRY_VERIFY(!lastUserAgent.isEmpty());
QCOMPARE(lastUserAgent, profile2.httpUserAgent().toUtf8());
@@ -4371,6 +4371,24 @@ void tst_QWebEnginePage::renderProcessCrashed()
status == QWebEnginePage::AbnormalTerminationStatus);
}
+void tst_QWebEnginePage::renderProcessPid()
+{
+ QCOMPARE(m_page->renderProcessPid(), 0);
+
+ m_page->load(QUrl("about:blank"));
+ QSignalSpy spyFinished(m_page, &QWebEnginePage::loadFinished);
+ QVERIFY(spyFinished.wait());
+
+ QVERIFY(m_page->renderProcessPid() > 1);
+
+ bool crashed = false;
+ connect(m_page, &QWebEnginePage::renderProcessTerminated, [&]() { crashed = true; });
+ m_page->load(QUrl("chrome://crash"));
+ QTRY_VERIFY_WITH_TIMEOUT(crashed, 20000);
+
+ QCOMPARE(m_page->renderProcessPid(), 0);
+}
+
void tst_QWebEnginePage::backgroundColor()
{
QWebEngineProfile profile;
diff --git a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
index 128cf7ab9..80c6740b4 100644
--- a/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
+++ b/tests/auto/widgets/qwebengineprofile/tst_qwebengineprofile.cpp
@@ -71,6 +71,7 @@ private Q_SLOTS:
void urlSchemeHandlerInstallation();
void urlSchemeHandlerXhrStatus();
void urlSchemeHandlerScriptModule();
+ void urlSchemeHandlerLongReply();
void customUserAgent();
void httpAcceptLanguage();
void downloadItem();
@@ -172,7 +173,6 @@ public:
~AutoDir() { removeRecursively(); }
};
-
qint64 totalSize(QDir dir)
{
qint64 sum = 0;
@@ -355,7 +355,7 @@ protected:
memcpy(data, m_data.constData() + m_bytesRead, len);
m_bytesAvailable -= len;
m_bytesRead += len;
- } else if (m_data.size() > 0)
+ } else if (atEnd())
return -1;
return len;
@@ -760,6 +760,31 @@ void tst_QWebEngineProfile::urlSchemeHandlerScriptModule()
QCOMPARE(evaluateJavaScriptSync(&page, QStringLiteral("test")).toString(), QStringLiteral("SUCCESS"));
}
+class LongReplyUrlSchemeHandler : public QWebEngineUrlSchemeHandler
+{
+public:
+ LongReplyUrlSchemeHandler(QObject *parent = nullptr) : QWebEngineUrlSchemeHandler(parent) {}
+ ~LongReplyUrlSchemeHandler() {}
+
+ void requestStarted(QWebEngineUrlRequestJob *job)
+ {
+ QBuffer *buffer = new QBuffer(job);
+ buffer->setData(QByteArray(128 * 1024, ' ') +
+ "<html><head><title>Minify this!</title></head></html>");
+ job->reply("text/html", buffer);
+ }
+};
+
+void tst_QWebEngineProfile::urlSchemeHandlerLongReply()
+{
+ LongReplyUrlSchemeHandler handler;
+ QWebEngineProfile profile;
+ profile.installUrlSchemeHandler("aviancarrier", &handler);
+ QWebEnginePage page(&profile);
+ page.load(QUrl("aviancarrier:/"));
+ QTRY_COMPARE(page.title(), QString("Minify this!"));
+}
+
void tst_QWebEngineProfile::customUserAgent()
{
QString defaultUserAgent = QWebEngineProfile::defaultProfile()->httpUserAgent();
@@ -907,8 +932,6 @@ void tst_QWebEngineProfile::changeHttpAcceptLanguage()
void tst_QWebEngineProfile::changeUseForGlobalCertificateVerification()
{
- QSKIP("Needs 3rdparty fix");
-
TestServer server;
QVERIFY(server.start());
@@ -965,26 +988,32 @@ void tst_QWebEngineProfile::initiator()
InitiatorSpy handler;
QWebEngineProfile profile;
profile.installUrlSchemeHandler("foo", &handler);
- QWebEnginePage page(&profile);
+ QWebEnginePage page(&profile, nullptr);
QSignalSpy loadFinishedSpy(&page, SIGNAL(loadFinished(bool)));
+ page.load(QUrl("about:blank"));
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ loadFinishedSpy.clear();
// about:blank has a unique origin, so initiator should be QUrl("null")
evaluateJavaScriptSync(&page, "window.location = 'foo:bar'");
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ loadFinishedSpy.clear();
QCOMPARE(handler.initiator, QUrl("null"));
page.setHtml("", QUrl("http://test:123/foo%20bar"));
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ loadFinishedSpy.clear();
// baseUrl determines the origin, so QUrl("http://test:123")
evaluateJavaScriptSync(&page, "window.location = 'foo:bar'");
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
+ loadFinishedSpy.clear();
QCOMPARE(handler.initiator, QUrl("http://test:123"));
// Directly calling load/setUrl should have initiator QUrl(), meaning
// browser-initiated, trusted.
page.load(QUrl("foo:bar"));
- QVERIFY(loadFinishedSpy.wait());
+ QTRY_COMPARE(loadFinishedSpy.count(), 1);
QCOMPARE(handler.initiator, QUrl());
}
diff --git a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
index 2862be1dd..5e16361c5 100644
--- a/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
+++ b/tests/auto/widgets/qwebengineview/tst_qwebengineview.cpp
@@ -538,7 +538,7 @@ void tst_QWebEngineView::focusInputTypes()
// 'text' field
QPoint textInputCenter = elementCenter(webView.page(), "textInput");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -546,7 +546,7 @@ void tst_QWebEngineView::focusInputTypes()
// 'password' field
QPoint passwordInputCenter = elementCenter(webView.page(), "passwordInput");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText));
QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -554,7 +554,7 @@ void tst_QWebEngineView::focusInputTypes()
// 'tel' field
QPoint telInputCenter = elementCenter(webView.page(), "telInput");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, telInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, telInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("telInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhDialableCharactersOnly);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -562,7 +562,7 @@ void tst_QWebEngineView::focusInputTypes()
// 'number' field
QPoint numberInputCenter = elementCenter(webView.page(), "numberInput");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, numberInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, numberInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("numberInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhFormattedNumbersOnly);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -570,7 +570,7 @@ void tst_QWebEngineView::focusInputTypes()
// 'email' field
QPoint emailInputCenter = elementCenter(webView.page(), "emailInput");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, emailInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, emailInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("emailInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhEmailCharactersOnly);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -578,28 +578,28 @@ void tst_QWebEngineView::focusInputTypes()
// 'url' field
QPoint urlInputCenter = elementCenter(webView.page(), "urlInput");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, urlInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, urlInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("urlInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhUrlCharactersOnly | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase));
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'password' field
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText));
QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
QTRY_COMPARE(inputMethodQuery(Qt::ImEnabled).toBool(), imeHasHiddenTextCapability);
// 'text' type
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), Qt::ImhPreferLowercase);
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
QTRY_VERIFY(inputMethodQuery(Qt::ImEnabled).toBool());
// 'password' field
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("passwordInput"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhSensitiveData | Qt::ImhNoPredictiveText | Qt::ImhNoAutoUppercase | Qt::ImhHiddenText));
QVERIFY(!webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -607,7 +607,7 @@ void tst_QWebEngineView::focusInputTypes()
// 'text area' field
QPoint textAreaCenter = elementCenter(webView.page(), "textArea");
- QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, 0, textAreaCenter);
+ QTest::mouseClick(webView.focusProxy(), Qt::LeftButton, {}, textAreaCenter);
QTRY_COMPARE(evaluateJavaScriptSync(webView.page(), "document.activeElement.id").toString(), QStringLiteral("textArea"));
VERIFY_INPUTMETHOD_HINTS(webView.focusProxy()->inputMethodHints(), (Qt::ImhMultiLine | Qt::ImhPreferLowercase));
QVERIFY(webView.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
@@ -696,12 +696,12 @@ void tst_QWebEngineView::horizontalScrollbarTest()
QSignalSpy scrollSpy(view.page(), SIGNAL(scrollPositionChanged(QPointF)));
// Note: The test below assumes that the layout direction is Qt::LeftToRight.
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, QPoint(550, 595));
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, QPoint(550, 595));
scrollSpy.wait();
QVERIFY(view.page()->scrollPosition().x() > 0);
// Note: The test below assumes that the layout direction is Qt::LeftToRight.
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, QPoint(20, 595));
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, QPoint(20, 595));
scrollSpy.wait();
QVERIFY(view.page()->scrollPosition() == QPoint(0, 0));
}
@@ -1213,7 +1213,7 @@ void tst_QWebEngineView::changeLocale()
QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 20000);
QTRY_VERIFY(!toPlainTextSync(viewDE.page()).isEmpty());
- errorLines = toPlainTextSync(viewDE.page()).split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
+ errorLines = toPlainTextSync(viewDE.page()).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("Die Website ist nicht erreichbar"));
QLocale::setDefault(QLocale("en"));
@@ -1223,7 +1223,7 @@ void tst_QWebEngineView::changeLocale()
QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyEN.count(), 1, 20000);
QTRY_VERIFY(!toPlainTextSync(viewEN.page()).isEmpty());
- errorLines = toPlainTextSync(viewEN.page()).split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
+ errorLines = toPlainTextSync(viewEN.page()).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("This site can\xE2\x80\x99t be reached"));
// Reset error page
@@ -1236,7 +1236,7 @@ void tst_QWebEngineView::changeLocale()
QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpyDE.count(), 1, 20000);
QTRY_VERIFY(!toPlainTextSync(viewDE.page()).isEmpty());
- errorLines = toPlainTextSync(viewDE.page()).split(QRegularExpression("[\r\n]"), QString::SkipEmptyParts);
+ errorLines = toPlainTextSync(viewDE.page()).split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
QCOMPARE(errorLines.first().toUtf8(), QByteArrayLiteral("Die Website ist nicht erreichbar"));
}
@@ -1472,7 +1472,7 @@ void tst_QWebEngineView::mouseClick()
QVERIFY(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString().isEmpty());
textInputCenter = elementCenter(view.page(), "input");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
QCOMPARE(selectionChangedSpy.count(), 0);
QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
@@ -1493,7 +1493,7 @@ void tst_QWebEngineView::mouseClick()
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QStringLiteral("Company"));
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 2);
QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
@@ -1514,7 +1514,7 @@ void tst_QWebEngineView::mouseClick()
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input"));
QCOMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString(), QStringLiteral("The Qt Company"));
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 3);
QVERIFY(view.focusProxy()->inputMethodQuery(Qt::ImCurrentSelection).toString().isEmpty());
@@ -1709,7 +1709,7 @@ void tst_QWebEngineView::postData()
QStringList lines = QString::fromLocal8Bit(rawData).split("\r\n");
// examine request
- QStringList request = lines[0].split(" ", QString::SkipEmptyParts);
+ QStringList request = lines[0].split(" ", Qt::SkipEmptyParts);
bool requestOk = request.length() > 2
&& request[2].toUpper().startsWith("HTTP/")
&& request[0].toUpper() == "POST"
@@ -1991,7 +1991,7 @@ void tst_QWebEngineView::softwareInputPanel()
QVERIFY(loadFinishedSpy.wait());
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
// This part of the test checks if the SIP (Software Input Panel) is triggered,
@@ -2010,7 +2010,7 @@ void tst_QWebEngineView::softwareInputPanel()
QTRY_VERIFY(!testContext.isInputPanelVisible());
testContext.hideInputPanel();
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_VERIFY(testContext.isInputPanelVisible());
view.setHtml("<html><body><p id='para'>nothing to input here</p></body></html>");
@@ -2018,7 +2018,7 @@ void tst_QWebEngineView::softwareInputPanel()
testContext.hideInputPanel();
QPoint paraCenter = elementCenter(view.page(), "para");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, paraCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, paraCenter);
QVERIFY(!testContext.isInputPanelVisible());
@@ -2030,7 +2030,7 @@ void tst_QWebEngineView::softwareInputPanel()
QVERIFY(loadFinishedSpy.wait());
QPoint btnDivCenter = elementCenter(view.page(), "btnDiv");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, btnDivCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, btnDivCenter);
QVERIFY(!testContext.isInputPanelVisible());
}
@@ -2055,7 +2055,7 @@ void tst_QWebEngineView::inputContextQueryInput()
// Set focus on an input field.
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(testContext.infos.count(), 2);
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
foreach (const InputMethodInfo &info, testContext.infos) {
@@ -2204,7 +2204,7 @@ void tst_QWebEngineView::inputMethods()
QTRY_COMPARE(loadFinishedSpy.size(), 1);
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
// ImCursorRectangle
@@ -2305,7 +2305,7 @@ void tst_QWebEngineView::textSelectionInInputField()
// LEFT to RIGHT selection
// Mouse click event moves the current cursor to the end of the text
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImCursorPosition).toInt(), 11);
QTRY_COMPARE(view.focusProxy()->inputMethodQuery(Qt::ImAnchorPosition).toInt(), 11);
@@ -2347,7 +2347,7 @@ void tst_QWebEngineView::textSelectionInInputField()
// RIGHT to LEFT selection
// Deselect the selection (this moves the current cursor to the end of the text)
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 2);
@@ -2387,7 +2387,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QVERIFY(view.page()->selectedText().isEmpty());
// Simple click should not update text selection, however it updates selection bounds in Chromium
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center());
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center());
QCOMPARE(selectionChangedSpy.count(), 0);
QVERIFY(!view.hasSelection());
QVERIFY(view.page()->selectedText().isEmpty());
@@ -2400,7 +2400,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QCOMPARE(view.page()->selectedText(), QString("This is a text"));
// Deselect text by mouse click
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center());
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center());
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 2);
QVERIFY(!view.hasSelection());
@@ -2447,7 +2447,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
// Remove selection by clicking into an input field
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
QCOMPARE(selectionChangedSpy.count(), 2);
@@ -2462,7 +2462,7 @@ void tst_QWebEngineView::textSelectionOutOfInputField()
QCOMPARE(view.page()->selectedText(), QString("QtWebEngine"));
// Deselect input field's text by mouse click
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, view.geometry().center());
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, view.geometry().center());
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 4);
QVERIFY(!view.hasSelection());
@@ -2483,14 +2483,14 @@ void tst_QWebEngineView::hiddenText()
QVERIFY(loadFinishedSpy.wait());
QPoint passwordInputCenter = elementCenter(view.page(), "password1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, passwordInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, passwordInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("password1"));
QVERIFY(!view.focusProxy()->testAttribute(Qt::WA_InputMethodEnabled));
QVERIFY(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText);
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QTRY_COMPARE(evaluateJavaScriptSync(view.page(), "document.activeElement.id").toString(), QStringLiteral("input1"));
QVERIFY(!(view.focusProxy()->inputMethodHints() & Qt::ImhHiddenText));
}
@@ -3108,7 +3108,7 @@ void tst_QWebEngineView::globalMouseSelection()
// Deselect the selection (this moves the current cursor to the end of the text)
QPoint textInputCenter = elementCenter(view.page(), "input1");
- QTest::mouseClick(view.focusProxy(), Qt::LeftButton, 0, textInputCenter);
+ QTest::mouseClick(view.focusProxy(), Qt::LeftButton, {}, textInputCenter);
QVERIFY(selectionChangedSpy.wait());
QCOMPARE(selectionChangedSpy.count(), 2);
QVERIFY(QApplication::clipboard()->text(QClipboard::Selection).isEmpty());
@@ -3149,36 +3149,55 @@ void tst_QWebEngineView::noContextMenu()
void tst_QWebEngineView::contextMenu_data()
{
QTest::addColumn<int>("childrenCount");
+ QTest::addColumn<bool>("isCustomMenu");
QTest::addColumn<Qt::ContextMenuPolicy>("contextMenuPolicy");
- QTest::newRow("defaultContextMenu") << 1 << Qt::DefaultContextMenu;
- QTest::newRow("customContextMenu") << 1 << Qt::CustomContextMenu;
- QTest::newRow("preventContextMenu") << 0 << Qt::PreventContextMenu;
+ QTest::newRow("defaultContextMenu") << 1 << false << Qt::DefaultContextMenu;
+ QTest::newRow("customContextMenu") << 1 << true << Qt::CustomContextMenu;
+ QTest::newRow("preventContextMenu") << 0 << false << Qt::PreventContextMenu;
}
void tst_QWebEngineView::contextMenu()
{
QFETCH(int, childrenCount);
+ QFETCH(bool, isCustomMenu);
QFETCH(Qt::ContextMenuPolicy, contextMenuPolicy);
QWebEngineView view;
+ QMenu *customMenu = nullptr;
if (contextMenuPolicy == Qt::CustomContextMenu) {
- connect(&view, &QWebEngineView::customContextMenuRequested, [&view](const QPoint &pt) {
- QMenu* menu = new QMenu(&view);
- menu->addAction("Action1");
- menu->addAction("Action2");
- menu->popup(pt);
+ connect(&view, &QWebEngineView::customContextMenuRequested, [&view, &customMenu] (const QPoint &pt) {
+ Q_ASSERT(!customMenu);
+ customMenu = new QMenu(&view);
+ customMenu->addAction("Action1");
+ customMenu->addAction("Action2");
+ customMenu->popup(pt);
});
}
view.setContextMenuPolicy(contextMenuPolicy);
+
+ // input is supposed to be skipped before first real navigation in >= 79
+ QSignalSpy loadSpy(&view, &QWebEngineView::loadFinished);
+ view.load(QUrl("about:blank"));
view.resize(640, 480);
view.show();
+ QTRY_COMPARE(loadSpy.count(), 1);
QVERIFY(view.findChildren<QMenu *>().isEmpty());
QTest::mouseMove(view.windowHandle(), QPoint(10,10));
QTest::mouseClick(view.windowHandle(), Qt::RightButton);
- QTRY_COMPARE(view.findChildren<QMenu *>().count(), childrenCount);
+
+ // verify for zero children will always succeed, so should be tested with at least minor timeout
+ if (childrenCount <= 0) {
+ QVERIFY(!QTest::qWaitFor([&view] () { return view.findChildren<QMenu *>().count() > 0; }, 500));
+ } else {
+ QTRY_COMPARE(view.findChildren<QMenu *>().count(), childrenCount);
+ if (isCustomMenu) {
+ QCOMPARE(view.findChildren<QMenu *>().first(), customMenu);
+ }
+ }
+ QCOMPARE(!!customMenu, isCustomMenu);
}
void tst_QWebEngineView::mouseLeave()
diff --git a/tests/auto/widgets/schemes/tst_schemes.cpp b/tests/auto/widgets/schemes/tst_schemes.cpp
index 1b6093571..a4a0e34ff 100644
--- a/tests/auto/widgets/schemes/tst_schemes.cpp
+++ b/tests/auto/widgets/schemes/tst_schemes.cpp
@@ -38,6 +38,7 @@ class tst_Schemes : public QObject
Q_OBJECT
private Q_SLOTS:
+ void unknownUrlSchemePolicy_data();
void unknownUrlSchemePolicy();
};
@@ -58,8 +59,27 @@ public:
}
};
+Q_DECLARE_METATYPE(QWebEngineSettings::UnknownUrlSchemePolicy)
+
+void tst_Schemes::unknownUrlSchemePolicy_data()
+{
+ QTest::addColumn<QWebEngineSettings::UnknownUrlSchemePolicy>("policy");
+ QTest::addColumn<bool>("userAction");
+ QTest::newRow("DisallowUnknownUrlSchemes, script") << QWebEngineSettings::DisallowUnknownUrlSchemes << false;
+ QTest::newRow("DisallowUnknownUrlSchemes, user") << QWebEngineSettings::DisallowUnknownUrlSchemes << true;
+ QTest::newRow("AllowUnknownUrlSchemesFromUserInteraction, script") << QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction << false;
+ QTest::newRow("AllowUnknownUrlSchemesFromUserInteraction, user") << QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction << true;
+ QTest::newRow("AllowAllUnknownUrlSchemes, script") << QWebEngineSettings::AllowAllUnknownUrlSchemes << false;
+ QTest::newRow("AllowAllUnknownUrlSchemes, user") << QWebEngineSettings::AllowAllUnknownUrlSchemes << true;
+ QTest::newRow("default UnknownUrlSchemePolicy, script") << QWebEngineSettings::UnknownUrlSchemePolicy(0) << false;
+ QTest::newRow("default UnknownUrlSchemePolicy, user") << QWebEngineSettings::UnknownUrlSchemePolicy(0) << true;
+}
+
void tst_Schemes::unknownUrlSchemePolicy()
{
+ QFETCH(QWebEngineSettings::UnknownUrlSchemePolicy, policy);
+ QFETCH(bool, userAction);
+
QWebEngineView view;
AcceptNavigationRequestHandler page;
QSignalSpy loadFinishedSpy(&page, &QWebEnginePage::loadFinished);
@@ -71,41 +91,31 @@ void tst_Schemes::unknownUrlSchemePolicy()
settings->setAttribute(QWebEngineSettings::ErrorPageEnabled, true);
settings->setAttribute(QWebEngineSettings::FocusOnNavigationEnabled, true);
- QWebEngineSettings::UnknownUrlSchemePolicy policies[6] = {QWebEngineSettings::DisallowUnknownUrlSchemes,
- QWebEngineSettings::DisallowUnknownUrlSchemes,
- QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction,
- QWebEngineSettings::AllowUnknownUrlSchemesFromUserInteraction,
- QWebEngineSettings::AllowAllUnknownUrlSchemes,
- QWebEngineSettings::AllowAllUnknownUrlSchemes};
- // even iterations are for navigation-requests from javascript,
- // odd iterations are for navigations-requests from user-interaction
- for (int i = 0; i < 8; i++) {
- if (i <= 5)
- settings->setUnknownUrlSchemePolicy(policies[i]);
- else
- settings->resetUnknownUrlSchemePolicy();
- loadFinishedSpy.clear();
- page.acceptNavigationRequestCalls = 0;
- bool shouldAccept;
-
- if (i % 2 == 0) { // navigation request coming from javascript
- shouldAccept = (4 <= i && i <= 5); // only case AllowAllUnknownUrlSchemes
- view.setHtml("<html><script>setTimeout(function(){ window.location.href='nonexistentscheme://somewhere'; }, 10);</script><body>testing...</body></html>");
- } else { // navigation request coming from user interaction
- shouldAccept = (2 <= i); // all cases except DisallowUnknownUrlSchemes
- view.setHtml("<html><body><a id='nonexlink' href='nonexistentscheme://somewhere'>nonexistentscheme://somewhere</a></body></html>");
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 15000);
- // focus and trigger the link
- view.page()->runJavaScript("document.getElementById('nonexlink').focus();", [&view](const QVariant &result) {
- Q_UNUSED(result);
- QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier);
- QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier);
- });
- }
+ if (policy > 0)
+ settings->setUnknownUrlSchemePolicy(policy);
+ else
+ settings->resetUnknownUrlSchemePolicy();
+ loadFinishedSpy.clear();
+ page.acceptNavigationRequestCalls = 0;
+ bool shouldAccept;
- QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 60000);
- QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0);
+ if (!userAction) { // navigation request coming from javascript
+ shouldAccept = (policy == QWebEngineSettings::AllowAllUnknownUrlSchemes);
+ view.setHtml("<html><script>setTimeout(function(){ window.location.href='nonexistentscheme://somewhere'; }, 10);</script><body>testing...</body></html>");
+ } else { // navigation request coming from user interaction
+ shouldAccept = (policy != QWebEngineSettings::DisallowUnknownUrlSchemes);
+ view.setHtml("<html><body><a id='nonexlink' href='nonexistentscheme://somewhere'>nonexistentscheme://somewhere</a></body></html>");
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 1, 15000);
+ // focus and trigger the link
+ view.page()->runJavaScript("document.getElementById('nonexlink').focus();", [&view](const QVariant &result) {
+ Q_UNUSED(result);
+ QTest::sendKeyEvent(QTest::Press, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier);
+ QTest::sendKeyEvent(QTest::Release, view.focusProxy(), Qt::Key_Return, QString("\r"), Qt::NoModifier);
+ });
}
+
+ QTRY_COMPARE_WITH_TIMEOUT(loadFinishedSpy.size(), 2, 60000);
+ QCOMPARE(page.acceptNavigationRequestCalls, shouldAccept ? 1 : 0);
}
QTEST_MAIN(tst_Schemes)
diff --git a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
index 64df05d89..801e2a76c 100644
--- a/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
+++ b/tests/auto/widgets/spellchecking/tst_spellchecking.cpp
@@ -41,10 +41,10 @@ public:
void activateMenu(QWidget *widget, const QPoint &position)
{
QTest::mouseMove(widget, position);
- QTest::mousePress(widget, Qt::RightButton, 0, position);
+ QTest::mousePress(widget, Qt::RightButton, {}, position);
QContextMenuEvent evcont(QContextMenuEvent::Mouse, position, mapToGlobal(position));
event(&evcont);
- QTest::mouseRelease(widget, Qt::RightButton, 0, position);
+ QTest::mouseRelease(widget, Qt::RightButton, {}, position);
}
const QWebEngineContextMenuData& data()
@@ -175,8 +175,8 @@ void tst_Spellchecking::spellcheck()
//type text, spellchecker needs time
QTest::mouseMove(m_view->focusWidget(), QPoint(20,20));
- QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20));
- QTest::mouseRelease(m_view->focusWidget(), Qt::LeftButton, 0, QPoint(20,20));
+ QTest::mousePress(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20));
+ QTest::mouseRelease(m_view->focusWidget(), Qt::LeftButton, {}, QPoint(20,20));
QString text("I lowe Qt ....");
for (int i = 0; i < text.length(); i++) {
QTest::keyClicks(m_view->focusWidget(), text.at(i));
diff --git a/tests/auto/widgets/util.h b/tests/auto/widgets/util.h
index eba974f33..20241be8b 100644
--- a/tests/auto/widgets/util.h
+++ b/tests/auto/widgets/util.h
@@ -132,7 +132,7 @@ static inline QString toHtmlSync(QWebEnginePage *page)
static inline bool findTextSync(QWebEnginePage *page, const QString &subString)
{
CallbackSpy<bool> spy;
- page->findText(subString, 0, spy.ref());
+ page->findText(subString, {}, spy.ref());
return spy.waitForResult();
}
diff --git a/tests/manual/quick/pdf/listview.qml b/tests/manual/quick/pdf/listview.qml
new file mode 100644
index 000000000..361ae7d89
--- /dev/null
+++ b/tests/manual/quick/pdf/listview.qml
@@ -0,0 +1,95 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+import QtQuick.Window 2.14
+import QtQuick.Pdf 5.15
+
+Window {
+ width: 600
+ height: 440
+ color: "lightgrey"
+ title: doc.source
+ visible: true
+
+ PdfDocument {
+ id: doc
+ source: "test.pdf"
+ }
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+ model: doc.pageCount
+ spacing: 6
+ delegate: Column {
+ Rectangle {
+ id: paper
+ width: image.width
+ height: image.height
+ Image {
+ id: image
+ objectName: "PDF page " + index
+ source: doc.source
+ currentFrame: index
+ asynchronous: true
+ }
+ }
+ Text {
+ text: "Page " + (image.currentFrame + 1)
+ }
+ }
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ text: "page " + Math.max(1, (listView.indexAt(0, listView.contentY) + 1)) + " of " + doc.pageCount
+ }
+}
diff --git a/tests/manual/quick/pdf/pessimizedListView.qml b/tests/manual/quick/pdf/pessimizedListView.qml
new file mode 100644
index 000000000..4ae0edabe
--- /dev/null
+++ b/tests/manual/quick/pdf/pessimizedListView.qml
@@ -0,0 +1,174 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import QtQuick.Layouts 1.14
+import QtQuick.Pdf 5.15
+import Qt.labs.platform 1.1 as P
+
+ApplicationWindow {
+ width: 900
+ height: 1000
+ color: "lightgrey"
+ title: doc.source + " scale " + imageScale.toFixed(2)
+ visible: true
+ property real imageScale: 1
+
+ header: ToolBar {
+ RowLayout {
+ anchors.fill: parent
+ anchors.rightMargin: 6
+ ToolButton {
+ action: Action {
+ text: "🗁"
+ shortcut: StandardKey.Open
+ onTriggered: fileDialog.open()
+ }
+ }
+ ToolButton {
+ action: Action {
+ text: "⊕"
+ shortcut: StandardKey.ZoomIn
+ onTriggered: imageScale *= Math.sqrt(2)
+ }
+ }
+ ToolButton {
+ action: Action {
+ text: "⊖"
+ shortcut: StandardKey.ZoomOut
+ onTriggered: imageScale /= Math.sqrt(2)
+ }
+ }
+ ToolButton {
+ action: Action {
+ text: "1x"
+ shortcut: "Ctrl+0"
+ onTriggered: imageScale = 1
+ }
+ }
+
+ Label {
+ text: "Pixels/point:"
+ }
+ SpinBox {
+ id: oversamplingSB
+ from: 1; to: 8; value: 4
+ }
+
+ Label {
+ text: "cacheBuffer:"
+ }
+ SpinBox {
+ id: cacheBufferSB
+ from: 0; to: 1000; stepSize: 50; value: 100
+ }
+
+ CheckBox {
+ id: asyncCB
+ text: "async"
+ }
+
+ CheckBox {
+ id: cacheCB
+ text: "cache"
+ }
+ }
+ }
+
+ PdfDocument {
+ id: doc
+ source: "test.pdf"
+ }
+
+ P.FileDialog {
+ id: fileDialog
+ title: "Open a PDF file"
+ nameFilters: [ "PDF files (*.pdf)" ]
+ onAccepted: doc.source = file
+ }
+
+ ListView {
+ id: listView
+ anchors.fill: parent
+ anchors.margins: 10
+ model: doc.pageCount
+ spacing: 6
+ cacheBuffer: cacheBufferSB.value
+ ScrollBar.vertical: ScrollBar { }
+ delegate: Rectangle {
+ id: paper
+ width: Math.max(60, image.width) * imageScale
+ height: 100 * imageScale
+ BusyIndicator {
+ anchors.centerIn: parent
+ running: image.status === Image.Loading
+ }
+ Image {
+ id: image
+ scale: imageScale
+ anchors.centerIn: parent
+ sourceSize.width: doc.pagePointSize(index).width * oversamplingSB.value
+ height: 100
+ fillMode: Image.PreserveAspectFit
+ objectName: "PDF page " + index
+ source: doc.source
+ currentFrame: index
+ asynchronous: asyncCB.checked
+ cache: cacheCB.checked
+ }
+ }
+ }
+
+ Text {
+ anchors.bottom: parent.bottom
+ anchors.right: parent.right
+ text: "page " + Math.max(1, (listView.indexAt(0, listView.contentY) + 1)) + " of " + doc.pageCount
+ }
+}
diff --git a/tests/manual/quick/pdf/simplest.qml b/tests/manual/quick/pdf/simplest.qml
new file mode 100644
index 000000000..0571493af
--- /dev/null
+++ b/tests/manual/quick/pdf/simplest.qml
@@ -0,0 +1,66 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+
+Image {
+ id: image
+ source: "test.pdf"
+ fillMode: Image.PreserveAspectFit
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ enabled: image.currentFrame < image.frameCount - 1
+ onActivated: image.currentFrame++
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ enabled: image.currentFrame > 0
+ onActivated: image.currentFrame--
+ }
+}
diff --git a/tests/manual/quick/pdf/test.pdf b/tests/manual/quick/pdf/test.pdf
new file mode 100644
index 000000000..a9dc1bc29
--- /dev/null
+++ b/tests/manual/quick/pdf/test.pdf
Binary files differ
diff --git a/tests/manual/quick/pdf/withdoc.qml b/tests/manual/quick/pdf/withdoc.qml
new file mode 100644
index 000000000..2d82a6abf
--- /dev/null
+++ b/tests/manual/quick/pdf/withdoc.qml
@@ -0,0 +1,206 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+import QtQuick 2.14
+import QtQuick.Controls 2.14
+import Qt.labs.platform 1.1 as Platform
+import QtQuick.Pdf 5.15
+import QtQuick.Shapes 1.14
+import QtQuick.Window 2.14
+
+Window {
+ width: 800
+ height: 940
+ color: "lightgrey"
+ title: doc.source
+ visible: true
+
+ PdfDocument {
+ id: doc
+ source: "test.pdf"
+ }
+
+ Platform.FileDialog {
+ id: fileDialog
+ title: "Open a PDF file"
+ nameFilters: [ "PDF files (*.pdf)" ]
+ onAccepted: doc.source = file
+ }
+
+ PdfSelection {
+ id: selection
+ document: doc
+ page: image.currentFrame
+ fromPoint: dragHandler.centroid.pressPosition
+ toPoint: dragHandler.centroid.position
+ hold: !dragHandler.active
+ }
+
+ Column {
+ id: column
+ anchors.fill: parent
+ anchors.margins: 6
+ spacing: 6
+ Text { text: "title: " + doc.title; visible: doc.title !== "" }
+ Text { text: "author: " + doc.author; visible: doc.author !== "" }
+ Text { text: "subject: " + doc.subject; visible: doc.subject !== "" }
+ Text { text: "keywords: " + doc.keywords; visible: doc.keywords !== "" }
+ Text { text: "producer: " + doc.producer; visible: doc.producer !== "" }
+ Text { text: "creator: " + doc.creator; visible: doc.creator !== "" }
+ Text { text: "creationDate: " + doc.creationDate; visible: doc.creationDate !== "" }
+ Text { text: "modificationDate: " + doc.modificationDate; visible: doc.modificationDate !== "" }
+ Text { text: "implicit size: " + image.implicitWidth + "x" + image.implicitHeight }
+ Text { text: "source size: " + image.sourceSize.width + "x" + image.sourceSize.height }
+ Text { text: "painted size: " + image.paintedWidth + "x" + image.paintedHeight }
+
+ Flickable {
+ width: column.width
+ height: width
+ contentWidth: paper.width
+ contentHeight: paper.height
+ z: -1
+ Rectangle {
+ id: paper
+ width: image.width
+ height: image.height
+ Image {
+ id: image
+ source: doc.status === PdfDocument.Ready ? doc.source : ""
+
+ property real zoomFactor: Math.sqrt(2)
+
+ DragHandler {
+ id: dragHandler
+ target: null
+ }
+
+ Shortcut {
+ sequence: StandardKey.MoveToNextPage
+ enabled: image.currentFrame < image.frameCount - 1
+ onActivated: image.currentFrame++
+ }
+ Shortcut {
+ sequence: StandardKey.MoveToPreviousPage
+ enabled: image.currentFrame > 0
+ onActivated: image.currentFrame--
+ }
+ Shortcut {
+ sequence: StandardKey.ZoomIn
+ enabled: image.sourceSize.width < 5000
+ onActivated: {
+ image.sourceSize.width = image.implicitWidth * image.zoomFactor
+ image.sourceSize.height = image.implicitHeight * image.zoomFactor
+ }
+ }
+ Shortcut {
+ sequence: StandardKey.ZoomOut
+ enabled: image.width > 50
+ onActivated: {
+ image.sourceSize.width = image.implicitWidth / image.zoomFactor
+ image.sourceSize.height = image.implicitHeight / image.zoomFactor
+ }
+ }
+ Shortcut {
+ sequence: "Ctrl+0"
+ onActivated: image.sourceSize = undefined
+ }
+ Shortcut {
+ sequence: StandardKey.Open
+ onActivated: fileDialog.open()
+ }
+ Shortcut {
+ sequence: StandardKey.Quit
+ onActivated: Qt.quit()
+ }
+ }
+
+ Shape {
+ anchors.fill: parent
+ opacity: 0.25
+ ShapePath {
+ fillColor: "cyan"
+ PathMultiline {
+ id: selectionBoundaries
+ paths: selection.geometry
+ }
+ }
+ }
+
+ Repeater {
+ model: PdfLinkModel {
+ id: linkModel
+ document: doc
+ page: image.currentFrame
+ }
+ delegate: Rectangle {
+ color: "transparent"
+ border.color: "lightgrey"
+ x: rect.x
+ y: rect.y
+ width: rect.width
+ height: rect.height
+// HoverHandler { cursorShape: Qt.PointingHandCursor } // 5.15 onward (QTBUG-68073)
+ TapHandler {
+ onTapped: {
+ if (page >= 0)
+ image.currentFrame = page
+ else
+ Qt.openUrlExternally(url)
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ Text {
+ anchors.bottom: parent.bottom
+ text: "page " + (image.currentFrame + 1) + " of " + doc.pageCount
+ }
+}
diff --git a/tools/about_credits_entry.tmpl b/tools/about_credits_entry.tmpl
index 20bbb28a0..2bb9cff4e 100644
--- a/tools/about_credits_entry.tmpl
+++ b/tools/about_credits_entry.tmpl
@@ -1,5 +1,4 @@
/*!
-\contentspage qtwebengine-licensing.html
\page qtwebengine-3rdparty-{{name-sanitized}}.html attribution
\ingroup qtwebengine-licensing
\brief {{license-type}}
diff --git a/tools/scripts/git_submodule.py b/tools/scripts/git_submodule.py
index 684a8af67..edaed1ed2 100644
--- a/tools/scripts/git_submodule.py
+++ b/tools/scripts/git_submodule.py
@@ -61,6 +61,9 @@ class DEPSParser:
#result.update(self.custom_vars or {})
return result
+ def get_recursedeps(self):
+ return self.local_scope["recursedeps"]
+
def createSubmodulesFromScope(self, scope, os):
submodules = []
for dep in scope:
@@ -225,6 +228,9 @@ class Submodule:
# The submodule operations should be done relative to the current submodule's
# supermodule.
if self.topmost_supermodule_path_prefix:
+ if not os.path.isdir(self.path):
+ print '-- skipping ' + self.path + ' as dir has been stripped. --'
+ return
os.chdir(self.topmost_supermodule_path_prefix)
if os.path.isdir(self.path):
@@ -309,14 +315,14 @@ class Submodule:
os.chdir(oldCwd)
return flattened_submodules
- def readSubmodules(self):
+ def readSubmodules(self, use_deps=False):
submodules = []
- if self.ref:
+ if use_deps:
submodules = resolver.readSubmodules()
print 'DEPS file provides the following submodules:'
for submodule in submodules:
print '{:<80}'.format(submodule.pathRelativeToTopMostSupermodule()) + '{:<120}'.format(submodule.url) + submodule.ref
- else: # Try .gitmodules since no ref has been specified
+ else: # Try .gitmodules instead
gitmodules_file_name = '.gitmodules'
submodules = self.readSubmodulesFromGitModules(self, gitmodules_file_name, self.path)
return submodules
@@ -324,7 +330,7 @@ class Submodule:
def initSubmodules(self):
oldCwd = os.getcwd()
os.chdir(self.path)
- submodules = self.readSubmodules()
+ submodules = self.readSubmodules(True)
for submodule in submodules:
submodule.initialize()
subprocessCall(['git', 'commit', '-a', '--amend', '--no-edit'])
diff --git a/tools/scripts/take_snapshot.py b/tools/scripts/take_snapshot.py
index 741979a9e..dffdcbc11 100755
--- a/tools/scripts/take_snapshot.py
+++ b/tools/scripts/take_snapshot.py
@@ -68,41 +68,29 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('buildtools/third_party/libunwind')
or (file_path.startswith('chrome/') and
not file_path.startswith('chrome/VERSION') and
+ not file_path.startswith('chrome/app/resources/') and
+ not file_path.startswith('chrome/app/theme/') and
not file_path.startswith('chrome/browser/chrome_notification_types.h') and
- not '/app/theme/' in file_path and
- not '/app/resources/' in file_path and
- not '/browser/printing/' in file_path and
- not ('/browser/resources/' in file_path and not '/chromeos/' in file_path) and
- not '/renderer/resources/' in file_path and
- not 'repack_locales' in file_path and
- not 'third_party/chromevox' in file_path and
- not 'media/webrtc/desktop_media_list.h' in file_path and
- not 'media/webrtc/desktop_streams_registry.' in file_path and
- not 'browser/net/chrome_mojo_proxy_resolver_factory.' in file_path and
- not '/browser/accessibility/' in file_path and
- not '/browser/custom_handlers/' in file_path and
- not '/browser/devtools/' in file_path and
- not '/browser/ui/webui/' in file_path and
- not 'common/chrome_constants.' in file_path and
- not 'common/chrome_paths' in file_path and
- not 'common/chrome_switches.' in file_path and
- not 'common/content_restriction.h' in file_path and
- not 'common/custom_handlers/' in file_path and
- not 'common/spellcheck_' in file_path and
- not 'common/url_constants.' in file_path and
- not 'common/webui_url_constants.' in file_path and
- not '/extensions/api/' in file_path and
- not '/extensions/browser/api/' in file_path and
- not '/extensions/permissions/' in file_path and
- not '/renderer_host/pepper/' in file_path and
- not '/renderer/pepper/' in file_path and
- not '/spellchecker/' in file_path and
- not '/tools/convert_dict/' in file_path and
- not file_path.endswith('cf_resources.rc') and
- not file_path.endswith('version.py') and
+ not file_path.startswith('chrome/browser/accessibility/') and
+ not file_path.startswith('chrome/browser/custom_handlers/') and
+ not file_path.startswith('chrome/browser/devtools/') and
+ not file_path.startswith('chrome/browser/extensions/api/') and
+ not file_path.startswith('chrome/browser/media/webrtc/') and
+ not file_path.startswith('chrome/browser/net/') and
+ not file_path.startswith('chrome/browser/prefs/') and
+ not file_path.startswith('chrome/browser/printing/') and
+ not file_path.startswith('chrome/browser/renderer_host/') and
+ not file_path.startswith('chrome/browser/spellchecker') and
+ not file_path.startswith('chrome/browser/ui/webui/') and
+ not (file_path.startswith('chrome/browser/resources/') and
+ not '/chromeos/' in file_path and
+ not '/settings/' in file_path and
+ not '/mediarouter/' in file_path) and
+ not (file_path.startswith('chrome/common/') and not file_path.startswith('chrome/common/extensions/docs')) and
+ not file_path.startswith('chrome/renderer/') and
+ not file_path.startswith('chrome/tools/convert_dict/') and
not file_path.endswith('.grd') and
not file_path.endswith('.grdp') and
- not file_path.endswith('.json') and
not file_path.endswith('chrome_version.rc.version'))
or file_path.startswith('chrome_elf')
or file_path.startswith('chromecast')
@@ -144,14 +132,16 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('testing/buildbot')
or (file_path.startswith('third_party/') and (
file_path.startswith('third_party/WebKit/LayoutTests')
- or file_path.startswith('third_party/accessibility-audit')
+ or file_path.startswith('third_party/accessibility')
or file_path.startswith('third_party/afl')
or file_path.startswith('third_party/android_')
- or file_path.startswith('third_party/apache-win32')
+ or file_path.startswith('third_party/angle/third_party/deqp')
+ or file_path.startswith('third_party/angle/third_party/glmark2')
+ or file_path.startswith('third_party/angle/third_party/vulkan-validation-layers')
+ or file_path.startswith('third_party/apache-')
or file_path.startswith('third_party/arcode-android-sdk')
or file_path.startswith('third_party/ashmem')
or file_path.startswith('third_party/binutils')
- or file_path.startswith('third_party/bison')
or file_path.startswith('third_party/blink/perf_tests/')
or file_path.startswith('third_party/blink/web_tests/')
or file_path.startswith('third_party/breakpad/src/processor/testdata/')
@@ -167,10 +157,9 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('third_party/catapult/tracing/test_data/')
or file_path.startswith('third_party/chromevox')
or file_path.startswith('third_party/chromite')
- or file_path.startswith('third_party/closure_compiler')
or file_path.startswith('third_party/colorama')
or file_path.startswith('third_party/depot_tools')
- or file_path.startswith('third_party/elfutils')
+ or file_path.startswith('third_party/devtools-node-modules')
or file_path.startswith('third_party/fuschsia-sdk/')
or file_path.startswith('third_party/glslang/src/Test/')
or file_path.startswith('third_party/google_')
@@ -179,7 +168,6 @@ def isInChromiumBlacklist(file_path):
or file_path.startswith('third_party/icu/android')
or file_path.startswith('third_party/icu/cast')
or file_path.startswith('third_party/icu/chromeos')
- or file_path.startswith('third_party/icu/ios')
or file_path.startswith('third_party/instrumented_libraries')
or file_path.startswith('third_party/jsr-305')
or file_path.startswith('third_party/junit')
@@ -294,10 +282,10 @@ def clearDirectory(directory):
shutil.rmtree(direntry)
os.chdir(currentDir)
-def listFilesInCurrentRepository():
+def listFilesInCurrentRepository(use_deps=False):
currentRepo = GitSubmodule.Submodule(os.getcwd())
files = subprocess.check_output(['git', 'ls-files']).splitlines()
- submodules = currentRepo.readSubmodules()
+ submodules = currentRepo.readSubmodules(use_deps)
for submodule in submodules:
submodule_files = submodule.listFiles()
for submodule_file in submodule_files:
@@ -340,7 +328,7 @@ def exportChromium():
os.makedirs(third_party_chromium);
print 'exporting contents of:' + third_party_upstream_chromium
os.chdir(third_party_upstream_chromium)
- files = listFilesInCurrentRepository()
+ files = listFilesInCurrentRepository(True)
# Add LASTCHANGE files which are not tracked by git.
files.append('build/util/LASTCHANGE')
files.append('build/util/LASTCHANGE.committime')
diff --git a/tools/scripts/version_resolver.py b/tools/scripts/version_resolver.py
index 2cdc1e3fb..58d5aa19d 100644
--- a/tools/scripts/version_resolver.py
+++ b/tools/scripts/version_resolver.py
@@ -38,9 +38,9 @@ import json
import urllib2
import git_submodule as GitSubmodule
-chromium_version = '77.0.3865.98'
-chromium_branch = '3865'
-ninja_version = 'v1.9.0'
+chromium_version = '79.0.3945.147'
+chromium_branch = '3945'
+ninja_version = 'v1.8.2'
json_url = 'http://omahaproxy.appspot.com/all.json'
@@ -88,17 +88,24 @@ def readSubmodules():
for sub in git_submodules:
submodule_dict[sub.path] = sub
+ extradeps_dirs = parser.get_recursedeps()
# Add buildtools submodules
- buildtools_deps_file_path = "buildtools/DEPS"
- if (os.path.isfile(buildtools_deps_file_path)):
- with open(buildtools_deps_file_path, 'r') as buildtools_deps_file:
- buildtools_deps = buildtools_deps_file.read()
- if buildtools_deps:
- buildtools_parser = GitSubmodule.DEPSParser()
- buildtools_parser.topmost_supermodule_path_prefix = './buildtools/'
- buildtools_submodules = buildtools_parser.parse(buildtools_deps)
- for sub in buildtools_submodules:
- submodule_dict[sub.path] = sub
+ extradeps_dirs.append('buildtools')
+
+ for extradeps_dir in extradeps_dirs:
+ if extradeps_dir.startswith('src/'):
+ extradeps_dir = extradeps_dir[4:]
+ extra_deps_file_path = extradeps_dir + '/DEPS'
+ if (os.path.isfile(extra_deps_file_path)):
+ with open(extra_deps_file_path, 'r') as extra_deps_file:
+ extra_deps = extra_deps_file.read()
+ if extra_deps:
+ extradeps_parser = GitSubmodule.DEPSParser()
+ extradeps_parser.topmost_supermodule_path_prefix = extradeps_dir
+ extradeps_submodules = extradeps_parser.parse(extra_deps)
+ for sub in extradeps_submodules:
+ submodule_dict[sub.path] = sub
+
# Remove unwanted upstream submodules
for path in submodule_blacklist: