[Payment Request][Desktop] Enable WebAuthn dialog in Payment Handler.

This patch creates a WebContentsModalDialogManager for the payment
handler renderer to allow the display of WebAuthn request dialog on top
of a payment handler window on desktop.

A new WebContentsModalDialogManagerDelegate subclass is introduced so
the dialog manager can interact with the WebContents. This delegate
borrows the WebContentsModalDialogHost from the browser for painting
modal dialogs at the correct position.

Bug: 938491
Change-Id: I67e625296c698b511bc6c0650975e60e7c61e245
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1531303
Commit-Queue: Danyao Wang <danyao@chromium.org>
Reviewed-by: Avi Drissman <avi@chromium.org>
Reviewed-by: Rouslan Solomakhin <rouslan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#642933}
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index ed58c47..063b3f3 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -2728,6 +2728,8 @@
       "views/payments/error_message_view_controller.h",
       "views/payments/order_summary_view_controller.cc",
       "views/payments/order_summary_view_controller.h",
+      "views/payments/payment_handler_modal_dialog_manager_delegate.cc",
+      "views/payments/payment_handler_modal_dialog_manager_delegate.h",
       "views/payments/payment_handler_web_flow_view_controller.cc",
       "views/payments/payment_handler_web_flow_view_controller.h",
       "views/payments/payment_method_view_controller.cc",
diff --git a/chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.cc b/chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.cc
new file mode 100644
index 0000000..9e9a0d8
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.cc
@@ -0,0 +1,47 @@
+// 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 "chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.h"
+
+#include "chrome/browser/platform_util.h"
+#include "components/web_modal/web_contents_modal_dialog_host.h"
+#include "content/public/browser/web_contents.h"
+
+namespace payments {
+
+PaymentHandlerModalDialogManagerDelegate::
+    PaymentHandlerModalDialogManagerDelegate(
+        web_modal::WebContentsModalDialogHost* host)
+    : host_(host), web_contents_(nullptr) {
+  DCHECK(host);
+}
+
+void PaymentHandlerModalDialogManagerDelegate::SetWebContentsBlocked(
+    content::WebContents* web_contents,
+    bool blocked) {
+  DCHECK(web_contents);
+  DCHECK_EQ(web_contents_, web_contents);
+  if (!blocked) {
+    web_contents->Focus();
+  }
+}
+
+web_modal::WebContentsModalDialogHost*
+PaymentHandlerModalDialogManagerDelegate::GetWebContentsModalDialogHost() {
+  return host_;
+}
+
+bool PaymentHandlerModalDialogManagerDelegate::IsWebContentsVisible(
+    content::WebContents* web_contents) {
+  DCHECK_EQ(web_contents_, web_contents);
+  return platform_util::IsVisible(web_contents->GetNativeView());
+}
+
+void PaymentHandlerModalDialogManagerDelegate::SetWebContents(
+    content::WebContents* web_contents) {
+  DCHECK(web_contents);
+  web_contents_ = web_contents;
+}
+
+}  // namespace payments
diff --git a/chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.h b/chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.h
new file mode 100644
index 0000000..0ac1cf71
--- /dev/null
+++ b/chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.h
@@ -0,0 +1,59 @@
+// 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.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_HANDLER_MODAL_DIALOG_MANAGER_DELEGATE_H_
+#define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_HANDLER_MODAL_DIALOG_MANAGER_DELEGATE_H_
+
+#include "base/macros.h"
+#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace web_modal {
+class WebContentsModalDialogHost;
+}
+
+namespace payments {
+
+// A delegate for presenting modal dialogs that are triggered from a web-based
+// payment handler. Since the payment sheet is itself a modal dialog, the
+// WebContentsModalDialogHost is expected to be borrowed from the browser that
+// spawned the payment sheet.
+class PaymentHandlerModalDialogManagerDelegate
+    : public web_modal::WebContentsModalDialogManagerDelegate {
+ public:
+  // |host| must not be null.
+  explicit PaymentHandlerModalDialogManagerDelegate(
+      web_modal::WebContentsModalDialogHost* host);
+  ~PaymentHandlerModalDialogManagerDelegate() override {}
+
+  // Sets the |web_contents| that is behind the modal dialogs managed by this
+  // modal dialog manager. |web_contents| must not be null.
+  void SetWebContents(content::WebContents* web_contents);
+
+  // WebContentsModalDialogManagerDelegate:
+  // |web_contents| must not be null and is expected to be the same as the one
+  // provided to SetWebContents().
+  void SetWebContentsBlocked(content::WebContents* web_contents,
+                             bool blocked) override;
+  web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost()
+      override;
+  bool IsWebContentsVisible(content::WebContents* web_contents) override;
+
+ private:
+  // A not-owned pointer to the WebContentsModalDialogHost associated with the
+  // browser that spawned the payment handler.
+  web_modal::WebContentsModalDialogHost* host_;
+
+  // A not-owned pointer to the WebContents behind the modal dialogs.
+  content::WebContents* web_contents_;
+
+  DISALLOW_COPY_AND_ASSIGN(PaymentHandlerModalDialogManagerDelegate);
+};
+
+}  // namespace payments
+
+#endif  // CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_HANDLER_MODAL_DIALOG_MANAGER_DELEGATE_H_
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
index 7f5455c9..5cf42d5 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.cc
@@ -17,6 +17,8 @@
 #include "chrome/browser/ui/views/payments/payment_request_views_util.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/payments/content/origin_security_checker.h"
+#include "components/web_modal/web_contents_modal_dialog_manager.h"
+#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_process_host.h"
@@ -145,12 +147,12 @@
     PaymentRequestSpec* spec,
     PaymentRequestState* state,
     PaymentRequestDialogView* dialog,
-    content::WebContents* log_destination,
+    content::WebContents* payment_request_web_contents,
     Profile* profile,
     GURL target,
     PaymentHandlerOpenWindowCallback first_navigation_complete_callback)
     : PaymentRequestSheetController(spec, state, dialog),
-      log_(log_destination),
+      log_(payment_request_web_contents),
       profile_(profile),
       target_(target),
       show_progress_bar_(false),
@@ -160,7 +162,16 @@
       first_navigation_complete_callback_(
           std::move(first_navigation_complete_callback)),
       https_prefix_(base::UTF8ToUTF16(url::kHttpsScheme) +
-                    base::UTF8ToUTF16(url::kStandardSchemeSeparator)) {
+                    base::UTF8ToUTF16(url::kStandardSchemeSeparator)),
+      // Borrow the browser's WebContentModalDialogHost to display modal dialogs
+      // triggered by the payment handler's web view (e.g. WebAuthn dialogs).
+      // The browser's WebContentModalDialogHost is valid throughout the
+      // lifetime of this controller because the payment sheet itself is a modal
+      // dialog.
+      dialog_manager_delegate_(
+          static_cast<web_modal::WebContentsModalDialogManagerDelegate*>(
+              chrome::FindBrowserWithWebContents(payment_request_web_contents))
+              ->GetWebContentsModalDialogHost()) {
   progress_bar_->set_owned_by_client();
   progress_bar_->set_foreground_color(gfx::kGoogleBlue500);
   progress_bar_->set_background_color(SK_ColorTRANSPARENT);
@@ -184,6 +195,13 @@
   web_contents()->SetDelegate(this);
   web_view->LoadInitialURL(target_);
 
+  // Enable modal dialogs for web-based payment handlers.
+  dialog_manager_delegate_.SetWebContents(web_contents());
+  web_modal::WebContentsModalDialogManager::CreateForWebContents(
+      web_contents());
+  web_modal::WebContentsModalDialogManager::FromWebContents(web_contents())
+      ->SetDelegate(&dialog_manager_delegate_);
+
   // The webview must get an explicitly set height otherwise the layout doesn't
   // make it fill its container. This is likely because it has no content at the
   // time of first layout (nothing has loaded yet). Because of this, set it to.
diff --git a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
index f2577ef..f84aa4b 100644
--- a/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
+++ b/chrome/browser/ui/views/payments/payment_handler_web_flow_view_controller.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_HANDLER_WEB_FLOW_VIEW_CONTROLLER_H_
 #define CHROME_BROWSER_UI_VIEWS_PAYMENTS_PAYMENT_HANDLER_WEB_FLOW_VIEW_CONTROLLER_H_
 
+#include "chrome/browser/ui/views/payments/payment_handler_modal_dialog_manager_delegate.h"
 #include "chrome/browser/ui/views/payments/payment_request_sheet_controller.h"
 #include "components/payments/content/developer_console_logger.h"
 #include "components/payments/content/payment_request_display_manager.h"
@@ -32,17 +33,22 @@
       public content::WebContentsObserver {
  public:
   // This ctor forwards its first 3 args to PaymentRequestSheetController's
-  // ctor. |log_destination| is the page whose web developer console will print
-  // error messages. That should be the page that instantiated PaymentRequest
-  // for developer convinience. |profile| is the browser context used to create
-  // the new WebContents object that will navigate to |target|.
-  // |first_navigation_complete_callback| is invoked once the WebContents
-  // finishes the initial navigation to |target|.
+  // ctor.
+  // |payment_request_web_contents| is the page that initiated the
+  // PaymentRequest. It is used in two ways:
+  // - Its web developer console is used to print error messages.
+  // - Its WebContentModalDialogHost is lent to the payment handler for the
+  //   display of modal dialogs initiated from the payment handler's web
+  //   content.
+  // |profile| is the browser context used to create the new payment handler
+  // WebContents object that will navigate to |target|.
+  // |first_navigation_complete_callback| is invoked once the payment handler
+  // WebContents finishes the initial navigation to |target|.
   PaymentHandlerWebFlowViewController(
       PaymentRequestSpec* spec,
       PaymentRequestState* state,
       PaymentRequestDialogView* dialog,
-      content::WebContents* log_destination,
+      content::WebContents* payment_request_web_contents,
       Profile* profile,
       GURL target,
       PaymentHandlerOpenWindowCallback first_navigation_complete_callback);
@@ -88,6 +94,9 @@
   std::unique_ptr<views::Separator> separator_;
   PaymentHandlerOpenWindowCallback first_navigation_complete_callback_;
   base::string16 https_prefix_;
+  // Used to present modal dialog triggered from the payment handler web view,
+  // e.g. an authenticator dialog.
+  PaymentHandlerModalDialogManagerDelegate dialog_manager_delegate_;
 };
 
 }  // namespace payments