diff options
m--------- | src/3rdparty | 0 | ||||
-rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/core/configure/BUILD.root.gn.in | 3 | ||||
-rw-r--r-- | src/core/content_browser_client_qt.cpp | 44 | ||||
-rw-r--r-- | src/core/content_browser_client_qt.h | 5 | ||||
-rw-r--r-- | src/core/extensions/extension_web_contents_observer_qt.cpp | 24 | ||||
-rw-r--r-- | src/core/extensions/extension_web_contents_observer_qt.h | 1 | ||||
-rw-r--r-- | src/core/extensions/pdf_web_contents_helper_client_qt.h | 26 | ||||
-rw-r--r-- | src/core/net/plugin_response_interceptor_url_loader_throttle.cpp | 46 | ||||
-rw-r--r-- | src/core/printing/pdf_stream_delegate_qt.cpp | 91 | ||||
-rw-r--r-- | src/core/printing/pdf_stream_delegate_qt.h | 23 | ||||
-rw-r--r-- | src/core/printing/pdf_web_contents_helper_client_qt.cpp | 56 | ||||
-rw-r--r-- | src/core/printing/pdf_web_contents_helper_client_qt.h | 27 | ||||
-rw-r--r-- | src/core/render_widget_host_view_qt.cpp | 2 | ||||
-rw-r--r-- | src/core/render_widget_host_view_qt.h | 2 | ||||
-rw-r--r-- | src/core/renderer/content_renderer_client_qt.cpp | 85 | ||||
-rw-r--r-- | src/core/web_contents_adapter.cpp | 7 |
17 files changed, 396 insertions, 48 deletions
diff --git a/src/3rdparty b/src/3rdparty -Subproject c575922203206b5cddb0fcfd492e0e0a4147c3c +Subproject 8496e134077ac79bb185d7d0f0333cdddb27a67 diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a9c31f911..b8ee2b8e4 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -225,6 +225,8 @@ foreach(arch ${archs}) extend_gn_target(${buildGn} CONDITION QT_FEATURE_webengine_printing_and_pdf SOURCES printing/pdfium_document_wrapper_qt.cpp printing/pdfium_document_wrapper_qt.h + printing/pdf_web_contents_helper_client_qt.cpp printing/pdf_web_contents_helper_client_qt.h + printing/pdf_stream_delegate_qt.cpp printing/pdf_stream_delegate_qt.h printing/print_view_manager_base_qt.cpp printing/print_view_manager_base_qt.h printing/print_view_manager_qt.cpp printing/print_view_manager_qt.h printing/printer_worker.cpp printing/printer_worker.h diff --git a/src/core/configure/BUILD.root.gn.in b/src/core/configure/BUILD.root.gn.in index 9a49d6465..24e8563eb 100644 --- a/src/core/configure/BUILD.root.gn.in +++ b/src/core/configure/BUILD.root.gn.in @@ -219,6 +219,7 @@ source_set("qtwebengine_sources") { "//components/plugins/renderer/", "//content/browser/resources/quota:resources", "//extensions/buildflags:buildflags", + "//pdf:buildflags", "//printing/buildflags:buildflags", "//qtwebengine/common:mojo_bindings", "//rlz/buildflags:buildflags", @@ -339,9 +340,9 @@ source_set("qtwebengine_sources") { if (enable_pdf) { deps += [ "//pdf", - "//pdf:buildflags", "//chrome/browser/resources/pdf:resources", "//components/pdf/browser", + "//components/pdf/browser:interceptors", "//components/pdf/common", "//components/pdf/renderer", "//components/printing/browser", diff --git a/src/core/content_browser_client_qt.cpp b/src/core/content_browser_client_qt.cpp index 973517404..fdca05760 100644 --- a/src/core/content_browser_client_qt.cpp +++ b/src/core/content_browser_client_qt.cpp @@ -27,6 +27,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/shared_cors_origin_access_list.h" +#include "content/public/browser/url_loader_request_interceptor.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" @@ -35,6 +36,7 @@ #include "content/public/common/user_agent.h" #include "extensions/buildflags/buildflags.h" #include "mojo/public/cpp/bindings/self_owned_associated_receiver.h" +#include "pdf/buildflags.h" #include "net/ssl/client_cert_identity.h" #include "net/ssl/client_cert_store.h" #include "net/ssl/ssl_private_key.h" @@ -139,6 +141,14 @@ #include "printing/print_view_manager_qt.h" #endif +#if BUILDFLAG(ENABLE_PDF) +#include "printing/pdf_stream_delegate_qt.h" + +#include "components/pdf/browser/pdf_navigation_throttle.h" +#include "components/pdf/browser/pdf_url_loader_request_interceptor.h" +#include "components/pdf/browser/pdf_web_contents_helper.h" +#endif + #include <QGuiApplication> #include <QStandardPaths> #include <qpa/qplatformnativeinterface.h> @@ -501,7 +511,14 @@ void ContentBrowserClientQt::RegisterAssociatedInterfaceBindersForRenderFrameHos mojo::PendingAssociatedReceiver<autofill::mojom::AutofillDriver> receiver) { autofill::ContentAutofillDriverFactory::BindAutofillDriver(std::move(receiver), render_frame_host); }, &rfh)); - +#if BUILDFLAG(ENABLE_PDF) + associated_registry.AddInterface( + base::BindRepeating( + [](content::RenderFrameHost *render_frame_host, + mojo::PendingAssociatedReceiver<pdf::mojom::PdfService> receiver) { + pdf::PDFWebContentsHelper::BindPdfService(std::move(receiver), render_frame_host); + }, &rfh)); +#endif // BUILDFLAG(ENABLE_PDF) ContentBrowserClient::RegisterAssociatedInterfaceBindersForRenderFrameHost(rfh, associated_registry); } @@ -829,6 +846,9 @@ std::vector<std::unique_ptr<content::NavigationThrottle>> ContentBrowserClientQt #if BUILDFLAG(ENABLE_EXTENSIONS) MaybeAddThrottle(extensions::PDFIFrameNavigationThrottleQt::MaybeCreateThrottleFor(navigation_handle), &throttles); #endif +#if BUILDFLAG(ENABLE_PDF) + MaybeAddThrottle(pdf::PdfNavigationThrottle::MaybeCreateThrottleFor(navigation_handle, std::make_unique<PdfStreamDelegateQt>()), &throttles); +#endif // BUILDFLAG(ENABLE_PDF) return throttles; } @@ -1153,6 +1173,9 @@ base::flat_set<std::string> ContentBrowserClientQt::GetPluginMimeTypesWithExtern } } #endif +#if BUILDFLAG(ENABLE_PDF) + mime_types.insert("application/x-google-chrome-pdf"); +#endif return mime_types; } @@ -1190,6 +1213,25 @@ bool ContentBrowserClientQt::WillCreateURLLoaderFactory( return true; } +std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> +ContentBrowserClientQt::WillCreateURLLoaderRequestInterceptors(content::NavigationUIData* navigation_ui_data, + int frame_tree_node_id, + const scoped_refptr<network::SharedURLLoaderFactory>& network_loader_factory) +{ + std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> interceptors; +#if BUILDFLAG(ENABLE_PDF) + { + std::unique_ptr<content::URLLoaderRequestInterceptor> pdf_interceptor = + pdf::PdfURLLoaderRequestInterceptor::MaybeCreateInterceptor( + frame_tree_node_id, std::make_unique<PdfStreamDelegateQt>()); + if (pdf_interceptor) + interceptors.push_back(std::move(pdf_interceptor)); + } +#endif + + return interceptors; +} + bool ContentBrowserClientQt::WillInterceptWebSocket(content::RenderFrameHost *frame) { Q_UNUSED(frame); diff --git a/src/core/content_browser_client_qt.h b/src/core/content_browser_client_qt.h index cba68b5d5..4ee5c0228 100644 --- a/src/core/content_browser_client_qt.h +++ b/src/core/content_browser_client_qt.h @@ -192,7 +192,10 @@ public: bool HasErrorPage(int http_status_code, content::WebContents *contents) override; bool HasCustomSchemeHandler(content::BrowserContext *browser_context, const std::string &scheme) override; - + std::vector<std::unique_ptr<content::URLLoaderRequestInterceptor>> + WillCreateURLLoaderRequestInterceptors(content::NavigationUIData *navigation_ui_data, + int frame_tree_node_id, + const scoped_refptr<network::SharedURLLoaderFactory> &network_loader_factory) override; bool WillCreateURLLoaderFactory(content::BrowserContext *browser_context, content::RenderFrameHost *frame, int render_process_id, diff --git a/src/core/extensions/extension_web_contents_observer_qt.cpp b/src/core/extensions/extension_web_contents_observer_qt.cpp index 03f608227..22092be30 100644 --- a/src/core/extensions/extension_web_contents_observer_qt.cpp +++ b/src/core/extensions/extension_web_contents_observer_qt.cpp @@ -7,9 +7,8 @@ #include "extension_web_contents_observer_qt.h" -#include "components/guest_view/browser/guest_view_base.h" +#include "content/browser/renderer_host/render_frame_host_impl.h" #include "content/public/browser/child_process_security_policy.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 "extensions/browser/extension_registry.h" @@ -43,6 +42,17 @@ void ExtensionWebContentsObserverQt::RenderFrameCreated(content::RenderFrameHost { ExtensionWebContentsObserver::RenderFrameCreated(render_frame_host); + if (web_contents()->IsInnerWebContentsForGuest() && static_cast<content::RenderFrameHostImpl *>(render_frame_host)->is_local_root_subframe()) { + content::WebContents *parent = web_contents()->GetOutermostWebContents(); + QtWebEngineCore::RenderWidgetHostViewQt *main_rwhv = static_cast<QtWebEngineCore::RenderWidgetHostViewQt *>(parent->GetRenderWidgetHostView()); + // Main frame of guest WebContents + content::RenderWidgetHost *guest_render_widget_host = web_contents()->GetRenderViewHost()->GetWidget(); + main_rwhv->addGuest(guest_render_widget_host); + // The frame which holds the actual PDF content inside the guest + content::RenderWidgetHost *pdf_render_widget_host = render_frame_host->GetRenderWidgetHost(); + main_rwhv->addGuest(pdf_render_widget_host); + } + const Extension *extension = GetExtensionFromFrame(render_frame_host, false); if (!extension) return; @@ -54,16 +64,6 @@ void ExtensionWebContentsObserverQt::RenderFrameCreated(content::RenderFrameHost policy->GrantRequestOrigin(process_id, url::Origin::Create(GURL(blink::kChromeUIResourcesURL))); } -void ExtensionWebContentsObserverQt::RenderViewReady() -{ - if (web_contents()->IsInnerWebContentsForGuest()) { - content::RenderWidgetHost *render_widget_host = web_contents()->GetRenderViewHost()->GetWidget(); - content::WebContents *parent_web_contents = guest_view::GuestViewBase::GetTopLevelWebContents(web_contents()); - QtWebEngineCore::RenderWidgetHostViewQt *parent_rwhv = static_cast<QtWebEngineCore::RenderWidgetHostViewQt *>(parent_web_contents->GetRenderWidgetHostView()); - parent_rwhv->setGuest(static_cast<content::RenderWidgetHostImpl *>(render_widget_host)); - } -} - WEB_CONTENTS_USER_DATA_KEY_IMPL(ExtensionWebContentsObserverQt); } // namespace extensions diff --git a/src/core/extensions/extension_web_contents_observer_qt.h b/src/core/extensions/extension_web_contents_observer_qt.h index 7af1ee96d..ff50b28e2 100644 --- a/src/core/extensions/extension_web_contents_observer_qt.h +++ b/src/core/extensions/extension_web_contents_observer_qt.h @@ -25,7 +25,6 @@ public: // content::WebContentsObserver overrides. void RenderFrameCreated(content::RenderFrameHost *render_frame_host) override; - void RenderViewReady() override; private: friend class content::WebContentsUserData<ExtensionWebContentsObserverQt>; diff --git a/src/core/extensions/pdf_web_contents_helper_client_qt.h b/src/core/extensions/pdf_web_contents_helper_client_qt.h deleted file mode 100644 index 3465f946c..000000000 --- a/src/core/extensions/pdf_web_contents_helper_client_qt.h +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2014 The Chromium Authors. All rights reserved. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ -#define PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H_ - -#include "components/pdf/browser/pdf_web_contents_helper_client.h" - -namespace extensions { - -class PDFWebContentsHelperClientQt : public pdf::PDFWebContentsHelperClient -{ -public: - PDFWebContentsHelperClientQt(); - ~PDFWebContentsHelperClientQt() override; - -private: - // pdf::PDFWebContentsHelperClient: - void UpdateContentRestrictions(content::WebContents *contents, int content_restrictions) override; - void OnPDFHasUnsupportedFeature(content::WebContents *contents) override; - void OnSaveURL(content::WebContents *contents) override; -}; - -} // namespace extensions - -#endif // PDF_WEB_CONTENTS_HELPER_CLIENT_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 index f6b961018..1bcb3ddea 100644 --- a/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp +++ b/src/core/net/plugin_response_interceptor_url_loader_throttle.cpp @@ -30,6 +30,50 @@ #include <string> #include <tuple> +namespace { +void ClearAllButFrameAncestors(network::mojom::URLResponseHead *response_head) +{ + response_head->headers->RemoveHeader("Content-Security-Policy"); + response_head->headers->RemoveHeader("Content-Security-Policy-Report-Only"); + + if (!response_head->parsed_headers) + return; + + std::vector<network::mojom::ContentSecurityPolicyPtr> &csp = + response_head->parsed_headers->content_security_policy; + std::vector<network::mojom::ContentSecurityPolicyPtr> cleared; + + for (auto &policy : csp) { + auto frame_ancestors = policy->directives.find(network::mojom::CSPDirectiveName::FrameAncestors); + if (frame_ancestors == policy->directives.end()) + continue; + + auto cleared_policy = network::mojom::ContentSecurityPolicy::New(); + cleared_policy->self_origin = std::move(policy->self_origin); + cleared_policy->header = std::move(policy->header); + cleared_policy->header->header_value = ""; + cleared_policy->directives[network::mojom::CSPDirectiveName::FrameAncestors] = std::move(frame_ancestors->second); + + auto raw_frame_ancestors = policy->raw_directives.find(network::mojom::CSPDirectiveName::FrameAncestors); + DCHECK(raw_frame_ancestors != policy->raw_directives.end()); + + cleared_policy->header->header_value = "frame-ancestors " + raw_frame_ancestors->second; + response_head->headers->AddHeader( + cleared_policy->header->type == network::mojom::ContentSecurityPolicyType::kEnforce + ? "Content-Security-Policy" + : "Content-Security-Policy-Report-Only", + cleared_policy->header->header_value); + cleared_policy->raw_directives[network::mojom::CSPDirectiveName::FrameAncestors] = + std::move(raw_frame_ancestors->second); + + cleared.push_back(std::move(cleared_policy)); + } + + csp.swap(cleared); +} +} // namespace + + namespace QtWebEngineCore { PluginResponseInterceptorURLLoaderThrottle::PluginResponseInterceptorURLLoaderThrottle( @@ -73,7 +117,7 @@ void PluginResponseInterceptorURLLoaderThrottle::WillProcessResponse(const GURL // Content-Security-Policy, and does not currently respect the policy anyway. // Ignore CSP served on a PDF response. https://crbug.com/271452 if (extension_id == extension_misc::kPdfExtensionId && response_head->headers) - response_head->headers->RemoveHeader("Content-Security-Policy"); + ClearAllButFrameAncestors(response_head); MimeTypesHandler::ReportUsedHandler(extension_id); diff --git a/src/core/printing/pdf_stream_delegate_qt.cpp b/src/core/printing/pdf_stream_delegate_qt.cpp new file mode 100644 index 000000000..bb7b37532 --- /dev/null +++ b/src/core/printing/pdf_stream_delegate_qt.cpp @@ -0,0 +1,91 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// based on chrome/browser/pdf/chrome_pdf_stream_delegate.cc: + +#include "pdf_stream_delegate_qt.h" + +#include "base/no_destructor.h" +#include "chrome/grit/pdf_resources.h" +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" +#include "extensions/common/constants.h" +#include "ui/base/resource/resource_bundle.h" + +// Associates a `pdf::PdfStreamDelegate::StreamInfo` with a `WebContents`. +// `PdfStreamDelegateQt::MapToOriginalUrl()` initializes this in +// `PdfNavigationThrottle`, and then `PdfStreamDelegateQt::GetStreamInfo()` +// returns the stashed result to `PdfURLLoaderRequestInterceptor`. +class StreamInfoHelper : public content::WebContentsUserData<StreamInfoHelper> +{ +public: + absl::optional<pdf::PdfStreamDelegate::StreamInfo> TakeStreamInfo() + { return std::move(stream_info_); } + +private: + friend class content::WebContentsUserData<StreamInfoHelper>; + WEB_CONTENTS_USER_DATA_KEY_DECL(); + + StreamInfoHelper(content::WebContents *contents, + pdf::PdfStreamDelegate::StreamInfo stream_info) + : content::WebContentsUserData<StreamInfoHelper>(*contents), + stream_info_(std::move(stream_info)) {} + + absl::optional<pdf::PdfStreamDelegate::StreamInfo> stream_info_; +}; + +WEB_CONTENTS_USER_DATA_KEY_IMPL(StreamInfoHelper); + +PdfStreamDelegateQt::PdfStreamDelegateQt() = default; +PdfStreamDelegateQt::~PdfStreamDelegateQt() = default; + +absl::optional<GURL> PdfStreamDelegateQt::MapToOriginalUrl(content::WebContents *contents, const GURL &stream_url) +{ + StreamInfoHelper *helper = StreamInfoHelper::FromWebContents(contents); + if (helper) { + // PDF viewer and Print Preview only do this once per WebContents. + return absl::nullopt; + } + + GURL original_url; + StreamInfo info; + + extensions::MimeHandlerViewGuest *guest = + extensions::MimeHandlerViewGuest::FromWebContents(contents); + if (guest) { + base::WeakPtr<extensions::StreamContainer> stream = guest->GetStreamWeakPtr(); + if (!stream || stream->extension_id() != extension_misc::kPdfExtensionId || + stream->stream_url() != stream_url || + !stream->pdf_plugin_attributes()) { + return absl::nullopt; + } + + original_url = stream->original_url(); + info.background_color = base::checked_cast<SkColor>(stream->pdf_plugin_attributes()->background_color); + info.full_frame = !stream->embedded(); + info.allow_javascript = stream->pdf_plugin_attributes()->allow_javascript; + } else { + return absl::nullopt; + } + + static const base::NoDestructor<std::string> injected_script( + ui::ResourceBundle::GetSharedInstance().LoadDataResourceString( + IDR_PDF_PDF_INTERNAL_PLUGIN_WRAPPER_ROLLUP_JS)); + + info.stream_url = stream_url; + info.original_url = original_url; + info.injected_script = injected_script.get(); + StreamInfoHelper::CreateForWebContents(contents, std::move(info)); + return original_url; +} + +absl::optional<pdf::PdfStreamDelegate::StreamInfo> +PdfStreamDelegateQt::GetStreamInfo(content::WebContents *contents) +{ + StreamInfoHelper *helper = StreamInfoHelper::FromWebContents(contents); + if (!helper) + return absl::nullopt; + + // Only the call immediately following `MapToOriginalUrl()` requires a valid + // `StreamInfo`; subsequent calls should just get nothing. + return helper->TakeStreamInfo(); +} diff --git a/src/core/printing/pdf_stream_delegate_qt.h b/src/core/printing/pdf_stream_delegate_qt.h new file mode 100644 index 000000000..47621576f --- /dev/null +++ b/src/core/printing/pdf_stream_delegate_qt.h @@ -0,0 +1,23 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef PDF_STREAM_DELEGATE_QT_H +#define PDF_STREAM_DELEGATE_QT_H + +#include "components/pdf/browser/pdf_stream_delegate.h" + +// based on chrome/browser/pdf/chrome_pdf_stream_delegate.h: +class PdfStreamDelegateQt : public pdf::PdfStreamDelegate +{ +public: + PdfStreamDelegateQt(); + PdfStreamDelegateQt(const PdfStreamDelegateQt &) = delete; + PdfStreamDelegateQt operator=(const PdfStreamDelegateQt &) = delete; + ~PdfStreamDelegateQt() override; + + // pdf::PdfStreamDelegate: + absl::optional<GURL> MapToOriginalUrl(content::WebContents *contents, const GURL &stream_url) override; + absl::optional<StreamInfo> GetStreamInfo(content::WebContents *contents) override; +}; + +#endif // PDF_STREAM_DELEGATE_QT_H diff --git a/src/core/printing/pdf_web_contents_helper_client_qt.cpp b/src/core/printing/pdf_web_contents_helper_client_qt.cpp new file mode 100644 index 000000000..7c2a46ebf --- /dev/null +++ b/src/core/printing/pdf_web_contents_helper_client_qt.cpp @@ -0,0 +1,56 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +// based on chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.cc: + +#include "pdf_web_contents_helper_client_qt.h" + +#include "content/public/browser/render_process_host.h" +#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" +#include "extensions/common/constants.h" + +namespace { +bool IsPdfExtensionOrigin(const url::Origin &origin) +{ + return origin.scheme() == extensions::kExtensionScheme && + origin.host() == extension_misc::kPdfExtensionId; +} + +// from chrome/browser/pdf/pdf_frame_util.cc: +content::RenderFrameHost *FindPdfChildFrame(content::RenderFrameHost *rfh) +{ + if (!IsPdfExtensionOrigin(rfh->GetLastCommittedOrigin())) + return nullptr; + + content::RenderFrameHost *pdf_rfh = nullptr; + rfh->ForEachRenderFrameHost( + base::BindRepeating( + [](content::RenderFrameHost *&pdf_rfh, content::RenderFrameHost *rfh) { + if (!rfh->GetProcess()->IsPdf()) + return; + + DCHECK(IsPdfExtensionOrigin(rfh->GetParent()->GetLastCommittedOrigin())); + DCHECK(!pdf_rfh); + pdf_rfh = rfh; + }, std::ref(pdf_rfh))); + + return pdf_rfh; +} +} // namespace + +PDFWebContentsHelperClientQt::PDFWebContentsHelperClientQt() = default; +PDFWebContentsHelperClientQt::~PDFWebContentsHelperClientQt() = default; + +content::RenderFrameHost *PDFWebContentsHelperClientQt::FindPdfFrame(content::WebContents *contents) +{ + content::RenderFrameHost *main_frame = contents->GetMainFrame(); + content::RenderFrameHost *pdf_frame = FindPdfChildFrame(main_frame); + return pdf_frame ? pdf_frame : main_frame; +} + +void PDFWebContentsHelperClientQt::SetPluginCanSave(content::WebContents *contents, bool can_save) +{ + auto *guest_view = extensions::MimeHandlerViewGuest::FromWebContents(contents); + if (guest_view) + guest_view->SetPluginCanSave(can_save); +} diff --git a/src/core/printing/pdf_web_contents_helper_client_qt.h b/src/core/printing/pdf_web_contents_helper_client_qt.h new file mode 100644 index 000000000..ccc552986 --- /dev/null +++ b/src/core/printing/pdf_web_contents_helper_client_qt.h @@ -0,0 +1,27 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H +#define PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H + +#include "components/pdf/browser/pdf_web_contents_helper_client.h" + +// based on chrome/browser/ui/pdf/chrome_pdf_web_contents_helper_client.h: +class PDFWebContentsHelperClientQt : public pdf::PDFWebContentsHelperClient +{ +public: + PDFWebContentsHelperClientQt(); + PDFWebContentsHelperClientQt(const PDFWebContentsHelperClientQt&) = delete; + PDFWebContentsHelperClientQt& operator=(const PDFWebContentsHelperClientQt&) = delete; + ~PDFWebContentsHelperClientQt() override; + +private: + // pdf::PDFWebContentsHelperClient: + content::RenderFrameHost* FindPdfFrame(content::WebContents *contents) override; + void UpdateContentRestrictions(content::WebContents *contents, int content_restrictions) override {} + void OnPDFHasUnsupportedFeature(content::WebContents *contents) override {} + void OnSaveURL(content::WebContents *contents) override {} + void SetPluginCanSave(content::WebContents *contents, bool can_save) override; +}; + +#endif // PDF_WEB_CONTENTS_HELPER_CLIENT_QT_H diff --git a/src/core/render_widget_host_view_qt.cpp b/src/core/render_widget_host_view_qt.cpp index 3c47fed35..2de141bba 100644 --- a/src/core/render_widget_host_view_qt.cpp +++ b/src/core/render_widget_host_view_qt.cpp @@ -234,7 +234,7 @@ void RenderWidgetHostViewQt::setAdapterClient(WebContentsAdapterClient *adapterC m_adapterClient = nullptr; }); } -void RenderWidgetHostViewQt::setGuest(content::RenderWidgetHostImpl *rwh) +void RenderWidgetHostViewQt::addGuest(content::RenderWidgetHost *rwh) { rwh->AddInputEventObserver(m_guestInputEventObserver.get()); } diff --git a/src/core/render_widget_host_view_qt.h b/src/core/render_widget_host_view_qt.h index 75b0515f0..a7c7009f1 100644 --- a/src/core/render_widget_host_view_qt.h +++ b/src/core/render_widget_host_view_qt.h @@ -54,7 +54,7 @@ public: WebContentsAdapterClient *adapterClient() { return m_adapterClient; } void setAdapterClient(WebContentsAdapterClient *adapterClient); RenderWidgetHostViewQtDelegateClient *delegateClient() const { return m_delegateClient.get(); } - void setGuest(content::RenderWidgetHostImpl *); + void addGuest(content::RenderWidgetHost *); void InitAsChild(gfx::NativeView) override; void InitAsPopup(content::RenderWidgetHostView*, const gfx::Rect&, const gfx::Rect&) override; diff --git a/src/core/renderer/content_renderer_client_qt.cpp b/src/core/renderer/content_renderer_client_qt.cpp index 9bcbc4a9a..5544b08df 100644 --- a/src/core/renderer/content_renderer_client_qt.cpp +++ b/src/core/renderer/content_renderer_client_qt.cpp @@ -45,6 +45,8 @@ #include "ui/base/webui/jstemplate_builder.h" #if QT_CONFIG(webengine_printing_and_pdf) +#include "components/pdf/renderer/internal_plugin_renderer_helpers.h" +#include "components/pdf/renderer/pdf_internal_plugin_delegate.h" #include "renderer/print_web_view_helper_delegate_qt.h" #endif @@ -58,6 +60,7 @@ #if BUILDFLAG(ENABLE_EXTENSIONS) #include "common/extensions/extensions_client_qt.h" +#include "extensions/common/constants.h" #include "extensions/extensions_renderer_client_qt.h" #include "extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container_manager.h" #include "mojo/public/cpp/bindings/associated_remote.h" @@ -309,6 +312,66 @@ std::unique_ptr<blink::WebPrescientNetworking> ContentRendererClientQt::CreatePr return std::make_unique<network_hints::WebPrescientNetworkingImpl>(render_frame); } +namespace { +bool IsPdfExtensionOrigin(const url::Origin &origin) +{ +#if BUILDFLAG(ENABLE_EXTENSIONS) + return origin.scheme() == extensions::kExtensionScheme && + origin.host() == extension_misc::kPdfExtensionId; +#else + return false; +#endif +} + +#if BUILDFLAG(ENABLE_PLUGINS) +void AppendParams(const std::vector<content::WebPluginMimeType::Param> &additional_params, + blink::WebVector<blink::WebString> *existing_names, + blink::WebVector<blink::WebString> *existing_values) +{ + DCHECK(existing_names->size() == existing_values->size()); + size_t existing_size = existing_names->size(); + size_t total_size = existing_size + additional_params.size(); + + blink::WebVector<blink::WebString> names(total_size); + blink::WebVector<blink::WebString> values(total_size); + + for (size_t i = 0; i < existing_size; ++i) { + names[i] = (*existing_names)[i]; + values[i] = (*existing_values)[i]; + } + + for (size_t i = 0; i < additional_params.size(); ++i) { + names[existing_size + i] = blink::WebString::FromUTF16(additional_params[i].name); + values[existing_size + i] = blink::WebString::FromUTF16(additional_params[i].value); + } + + existing_names->Swap(names); + existing_values->Swap(values); +} +#endif // BUILDFLAG(ENABLE_PLUGINS) + +#if QT_CONFIG(webengine_printing_and_pdf) +// based on chrome/renderer/pdf/chrome_pdf_internal_plugin_delegate.cc: +class PdfInternalPluginDelegateQt final + : public pdf::PdfInternalPluginDelegate +{ +public: + PdfInternalPluginDelegateQt() = default; + PdfInternalPluginDelegateQt(const PdfInternalPluginDelegateQt &) = delete; + PdfInternalPluginDelegateQt& operator=(const PdfInternalPluginDelegateQt &) = delete; + ~PdfInternalPluginDelegateQt() override = default; + + // `pdf::PdfInternalPluginDelegate`: + bool IsAllowedOrigin(const url::Origin &origin) const override; +}; + +bool PdfInternalPluginDelegateQt::IsAllowedOrigin(const url::Origin &origin) const +{ + return IsPdfExtensionOrigin(origin); +} +#endif +} // namespace + bool ContentRendererClientQt::IsPluginHandledExternally(content::RenderFrame *render_frame, const blink::WebElement &plugin_element, const GURL &original_url, @@ -323,6 +386,8 @@ bool ContentRendererClientQt::IsPluginHandledExternally(content::RenderFrame *re original_url, original_mime_type, &found, &plugin_info, &mime_type); if (!found) return false; + if (IsPdfExtensionOrigin(render_frame->GetWebFrame()->GetSecurityOrigin())) + return true; return extensions::MimeHandlerViewContainerManager::Get( content::RenderFrame::FromWebFrame( plugin_element.GetDocument().GetFrame()), @@ -349,10 +414,24 @@ bool ContentRendererClientQt::OverrideCreatePlugin(content::RenderFrame *render_ static_cast<content::RenderFrameImpl *>(render_frame)->GetPepperHost()->GetPluginInfo( params.url, params.mime_type.Utf8(), &found, &info, &mime_type); - if (!found) + if (!found) { *plugin = LoadablePluginPlaceholderQt::CreateLoadableMissingPlugin(render_frame, params)->plugin(); - else - *plugin = render_frame->CreatePlugin(info, params); + return true; + } + if (info.name == u"Chromium PDF Viewer") { + blink::WebPluginParams new_params(params); + for (const auto& mime_type : info.mime_types) { + if (mime_type.mime_type == params.mime_type.Utf8()) { + AppendParams(mime_type.additional_params, &new_params.attribute_names, + &new_params.attribute_values); + break; + } + } + + *plugin = pdf::CreateInternalPlugin(std::move(new_params), render_frame, std::make_unique<PdfInternalPluginDelegateQt>()); + return true; + } + *plugin = render_frame->CreatePlugin(info, params); #endif // BUILDFLAG(ENABLE_PLUGINS) return true; } diff --git a/src/core/web_contents_adapter.cpp b/src/core/web_contents_adapter.cpp index 1f17d0398..7dc96967f 100644 --- a/src/core/web_contents_adapter.cpp +++ b/src/core/web_contents_adapter.cpp @@ -61,6 +61,8 @@ #include "qtwebengine/browser/qtwebenginepage.mojom.h" #if QT_CONFIG(webengine_printing_and_pdf) +#include "components/pdf/browser/pdf_web_contents_helper.h" +#include "printing/pdf_web_contents_helper_client_qt.h" #include "printing/print_view_manager_qt.h" #endif @@ -487,6 +489,11 @@ void WebContentsAdapter::initialize(content::SiteInstance *site) webContents(), AutofillClientQt::FromWebContents(webContents()), /* app_locale = */ "", autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); +#if QT_CONFIG(webengine_printing_and_pdf) + pdf::PDFWebContentsHelper::CreateForWebContentsWithClient( + webContents(), std::make_unique<PDFWebContentsHelperClientQt>()); +#endif + // Create an instance of WebEngineVisitedLinksManager to catch the first // content::NOTIFICATION_RENDERER_PROCESS_CREATED event. This event will // force to initialize visited links in VisitedLinkSlave. |