Introduce API for external handling of plugins

When the contents of a plugin element (<embed> and <object>) are to be
handeld externally inside an extension (most notably PDF) we currently
use browser plugin. BrowserPlugin is used to render GuestView contents
in another process.

However, BrowserPlugin-based guest views have been deprecated and all
guest views except for MimeHandlerViewGuest are not implemented on top
of cross-process frames.

This CL introduces the first steps in fully replacing BrowserPlugin with
corss-process frames.

Different mechanisms for this project have already been discussed in the
design doc:
https://docs.google.com/document/d/10g7Y9cprYKkch9JZ0TBUWaEnHBJT1nzhskQIt1nHbWM/edit#heading=h.ue5a8s290yhk

Bug: 659750, 330264
Change-Id: If273fbbab3e9f4a4591c61b19d54e4cca73c3464
Reviewed-on: https://chromium-review.googlesource.com/1101161
Reviewed-by: Ehsan Karamad <ekaramad@chromium.org>
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Ehsan Karamad <ekaramad@chromium.org>
Cr-Commit-Position: refs/heads/master@{#578554}
diff --git a/third_party/blink/public/web/web_local_frame_client.h b/third_party/blink/public/web/web_local_frame_client.h
index 1ce3fc4..a5c8b8e 100644
--- a/third_party/blink/public/web/web_local_frame_client.h
+++ b/third_party/blink/public/web/web_local_frame_client.h
@@ -827,6 +827,15 @@
   CreateWebSocketHandshakeThrottle() {
     return nullptr;
   }
+
+  // Returns true when the contents of plugin are handled externally. This means
+  // the plugin element will own a content frame but the frame is than used
+  // externally to load the required handelrs.
+  virtual bool IsPluginHandledExternally(const WebElement& plugin_element,
+                                         const WebURL& url,
+                                         const WebString& suggested_mime_type) {
+    return false;
+  }
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 6bf62e2..f79cb23 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -1114,6 +1114,14 @@
   web_frame_->Client()->FrameRectsChanged(frame_rect);
 }
 
+bool LocalFrameClientImpl::IsPluginHandledExternally(
+    HTMLPlugInElement& plugin_element,
+    const KURL& resource_url,
+    const String& suggesed_mime_type) {
+  return web_frame_->Client()->IsPluginHandledExternally(
+      &plugin_element, resource_url, suggesed_mime_type);
+}
+
 std::unique_ptr<WebWorkerFetchContext>
 LocalFrameClientImpl::CreateWorkerFetchContext() {
   DCHECK(web_frame_->Client());
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.h b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
index 14a451e9..e417ef7 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.h
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.h
@@ -277,6 +277,10 @@
 
   void FrameRectsChanged(const IntRect&) override;
 
+  bool IsPluginHandledExternally(HTMLPlugInElement&,
+                                 const KURL&,
+                                 const String&) override;
+
   std::unique_ptr<WebWorkerFetchContext> CreateWorkerFetchContext() override;
   std::unique_ptr<WebContentSettingsClient> CreateWorkerContentSettingsClient()
       override;
diff --git a/third_party/blink/renderer/core/frame/local_frame_client.h b/third_party/blink/renderer/core/frame/local_frame_client.h
index 7360a10..8f56be5 100644
--- a/third_party/blink/renderer/core/frame/local_frame_client.h
+++ b/third_party/blink/renderer/core/frame/local_frame_client.h
@@ -418,6 +418,15 @@
 
   virtual void FrameRectsChanged(const IntRect&) {}
 
+  // Returns true when the contents of plugin are handled externally. This means
+  // the plugin element will own a content frame but the frame is than used
+  // externally to load the required handelrs.
+  virtual bool IsPluginHandledExternally(HTMLPlugInElement&,
+                                         const KURL&,
+                                         const String&) {
+    return false;
+  };
+
   // Returns a new WebWorkerFetchContext for a dedicated worker or worklet.
   virtual std::unique_ptr<WebWorkerFetchContext> CreateWorkerFetchContext() {
     return nullptr;
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.cc b/third_party/blink/renderer/core/html/html_plugin_element.cc
index d849d69..47270324 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.cc
+++ b/third_party/blink/renderer/core/html/html_plugin_element.cc
@@ -69,6 +69,16 @@
   kPluginRequestObjectResultMax
 };
 
+String GetMIMETypeFromURL(const KURL& url) {
+  String filename = url.LastPathComponent();
+  int extension_pos = filename.ReverseFind('.');
+  if (extension_pos >= 0) {
+    String extension = filename.Substring(extension_pos + 1);
+    return MIMETypeRegistry::GetWellKnownMIMETypeForExtension(extension);
+  }
+  return String();
+}
+
 }  // anonymous namespace
 
 const Vector<String>& PluginParameters::Names() const {
@@ -148,6 +158,12 @@
 
 bool HTMLPlugInElement::RequestObjectInternal(
     const PluginParameters& plugin_params) {
+  if (handled_externally_) {
+    // TODO(ekaramad): Fix this once we know what to do with frames inside
+    // plugins (https://crbug.com/776510).
+    return true;
+  }
+
   if (url_.IsEmpty() && service_type_.IsEmpty())
     return false;
 
@@ -159,9 +175,20 @@
   if (!AllowedToLoadObject(completed_url, service_type_))
     return false;
 
+  handled_externally_ =
+      GetDocument().GetFrame()->Client()->IsPluginHandledExternally(
+          *this, completed_url,
+          service_type_.IsEmpty() ? GetMIMETypeFromURL(completed_url)
+                                  : service_type_);
+  if (handled_externally_) {
+    // This is a temporary placeholder and the logic around
+    // |handled_externally_| might change as MimeHandlerView is moving towards
+    // depending on OOPIFs instead of WebPlugin (https://crbug.com/659750).
+    completed_url = BlankURL();
+  }
   ObjectContentType object_type = GetObjectContentType();
   if (object_type == ObjectContentType::kFrame ||
-      object_type == ObjectContentType::kImage) {
+      object_type == ObjectContentType::kImage || handled_externally_) {
     // If the plugin element already contains a subframe,
     // loadOrRedirectSubframe will re-use it. Otherwise, it will create a
     // new frame and set it as the LayoutEmbeddedContent's EmbeddedContentView,
@@ -489,13 +516,7 @@
   KURL url = GetDocument().CompleteURL(url_);
   if (mime_type.IsEmpty()) {
     // Try to guess the MIME type based off the extension.
-    String filename = url.LastPathComponent();
-    int extension_pos = filename.ReverseFind('.');
-    if (extension_pos >= 0) {
-      String extension = filename.Substring(extension_pos + 1);
-      mime_type = MIMETypeRegistry::GetWellKnownMIMETypeForExtension(extension);
-    }
-
+    mime_type = GetMIMETypeFromURL(url);
     if (mime_type.IsEmpty())
       return ObjectContentType::kFrame;
   }
diff --git a/third_party/blink/renderer/core/html/html_plugin_element.h b/third_party/blink/renderer/core/html/html_plugin_element.h
index 62e6624..7581470c 100644
--- a/third_party/blink/renderer/core/html/html_plugin_element.h
+++ b/third_party/blink/renderer/core/html/html_plugin_element.h
@@ -224,6 +224,8 @@
   // off embedded_content_view_ here while the plugin is persisting but not
   // being displayed.
   Member<WebPluginContainerImpl> persisted_plugin_;
+
+  bool handled_externally_ = false;
 };
 
 inline bool IsHTMLPlugInElement(const HTMLElement& element) {