1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" 6 7#include "base/strings/stringprintf.h" 8#include "content/public/browser/browser_thread.h" 9#include "content/public/browser/render_process_host.h" 10#include "content/public/common/url_constants.h" 11#include "extensions/browser/api/extensions_api_client.h" 12#include "extensions/browser/extension_registry.h" 13#include "extensions/browser/extension_system.h" 14#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_constants.h" 15#include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest_delegate.h" 16#include "extensions/browser/process_manager.h" 17#include "extensions/common/extension_messages.h" 18#include "extensions/common/feature_switch.h" 19#include "extensions/common/guest_view/guest_view_constants.h" 20#include "extensions/strings/grit/extensions_strings.h" 21#include "ipc/ipc_message_macros.h" 22#include "net/base/url_util.h" 23 24using content::WebContents; 25 26namespace extensions { 27 28// static 29const char MimeHandlerViewGuest::Type[] = "mimehandler"; 30 31// static 32GuestViewBase* MimeHandlerViewGuest::Create( 33 content::BrowserContext* browser_context, 34 int guest_instance_id) { 35 if (!extensions::FeatureSwitch::mime_handler_view()->IsEnabled()) 36 return NULL; 37 38 return new MimeHandlerViewGuest(browser_context, guest_instance_id); 39} 40 41MimeHandlerViewGuest::MimeHandlerViewGuest( 42 content::BrowserContext* browser_context, 43 int guest_instance_id) 44 : GuestView<MimeHandlerViewGuest>(browser_context, guest_instance_id), 45 delegate_(ExtensionsAPIClient::Get()->CreateMimeHandlerViewGuestDelegate( 46 this)) { 47} 48 49MimeHandlerViewGuest::~MimeHandlerViewGuest() { 50} 51 52WindowController* MimeHandlerViewGuest::GetExtensionWindowController() const { 53 return NULL; 54} 55 56WebContents* MimeHandlerViewGuest::GetAssociatedWebContents() const { 57 return web_contents(); 58} 59 60const char* MimeHandlerViewGuest::GetAPINamespace() const { 61 return "mimeHandlerViewGuestInternal"; 62} 63 64int MimeHandlerViewGuest::GetTaskPrefix() const { 65 return IDS_EXTENSION_TASK_MANAGER_MIMEHANDLERVIEW_TAG_PREFIX; 66} 67 68// |embedder_extension_id| is empty for mime handler view. 69void MimeHandlerViewGuest::CreateWebContents( 70 const std::string& embedder_extension_id, 71 int embedder_render_process_id, 72 const GURL& embedder_site_url, 73 const base::DictionaryValue& create_params, 74 const WebContentsCreatedCallback& callback) { 75 std::string orig_mime_type; 76 create_params.GetString(mime_handler_view::kMimeType, &orig_mime_type); 77 DCHECK(!orig_mime_type.empty()); 78 79 std::string extension_src; 80 create_params.GetString(mime_handler_view::kSrc, &extension_src); 81 DCHECK(!extension_src.empty()); 82 83 GURL mime_handler_extension_url(extension_src); 84 if (!mime_handler_extension_url.is_valid()) { 85 callback.Run(NULL); 86 return; 87 } 88 89 const Extension* mime_handler_extension = 90 // TODO(lazyboy): Do we need handle the case where the extension is 91 // terminated (ExtensionRegistry::TERMINATED)? 92 ExtensionRegistry::Get(browser_context())->enabled_extensions().GetByID( 93 mime_handler_extension_url.host()); 94 if (!mime_handler_extension) { 95 LOG(ERROR) << "Extension for mime_type not found, mime_type = " 96 << orig_mime_type; 97 callback.Run(NULL); 98 return; 99 } 100 101 ProcessManager* process_manager = 102 ExtensionSystem::Get(browser_context())->process_manager(); 103 DCHECK(process_manager); 104 105 // Use the mime handler extension's SiteInstance to create the guest so it 106 // goes under the same process as the extension. 107 content::SiteInstance* guest_site_instance = 108 process_manager->GetSiteInstanceForURL( 109 Extension::GetBaseURLFromExtensionId(embedder_extension_id)); 110 111 WebContents::CreateParams params(browser_context(), guest_site_instance); 112 params.guest_delegate = this; 113 callback.Run(WebContents::Create(params)); 114} 115 116void MimeHandlerViewGuest::DidAttachToEmbedder() { 117 std::string src; 118 bool success = attach_params()->GetString(mime_handler_view::kSrc, &src); 119 DCHECK(success && !src.empty()); 120 web_contents()->GetController().LoadURL( 121 GURL(src), 122 content::Referrer(), 123 ui::PAGE_TRANSITION_AUTO_TOPLEVEL, 124 std::string()); 125} 126 127void MimeHandlerViewGuest::DidInitialize() { 128 extension_function_dispatcher_.reset( 129 new ExtensionFunctionDispatcher(browser_context(), this)); 130 if (delegate_) 131 delegate_->AttachHelpers(); 132} 133 134void MimeHandlerViewGuest::ContentsZoomChange(bool zoom_in) { 135 if (delegate_) 136 delegate_->ChangeZoom(zoom_in); 137} 138 139void MimeHandlerViewGuest::HandleKeyboardEvent( 140 WebContents* source, 141 const content::NativeWebKeyboardEvent& event) { 142 if (!attached()) 143 return; 144 145 // Send the keyboard events back to the embedder to reprocess them. 146 // TODO(fsamuel): This introduces the possibility of out-of-order keyboard 147 // events because the guest may be arbitrarily delayed when responding to 148 // keyboard events. In that time, the embedder may have received and processed 149 // additional key events. This needs to be fixed as soon as possible. 150 // See http://crbug.com/229882. 151 embedder_web_contents()->GetDelegate()->HandleKeyboardEvent(web_contents(), 152 event); 153} 154 155bool MimeHandlerViewGuest::OnMessageReceived(const IPC::Message& message) { 156 bool handled = true; 157 IPC_BEGIN_MESSAGE_MAP(MimeHandlerViewGuest, message) 158 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) 159 IPC_MESSAGE_UNHANDLED(handled = false) 160 IPC_END_MESSAGE_MAP() 161 return handled; 162} 163 164void MimeHandlerViewGuest::OnRequest( 165 const ExtensionHostMsg_Request_Params& params) { 166 if (extension_function_dispatcher_) { 167 extension_function_dispatcher_->Dispatch( 168 params, web_contents()->GetRenderViewHost()); 169 } 170} 171 172} // namespace extensions 173