OLD | NEW |
| (Empty) |
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 "chrome/browser/guest_view/extension_options/extension_options_guest.h" | |
6 | |
7 #include "base/values.h" | |
8 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h" | |
9 #include "chrome/browser/extensions/extension_tab_util.h" | |
10 #include "chrome/browser/guest_view/extension_options/extension_options_constant
s.h" | |
11 #include "chrome/browser/profiles/profile.h" | |
12 #include "chrome/browser/renderer_context_menu/render_view_context_menu.h" | |
13 #include "chrome/browser/ui/browser.h" | |
14 #include "chrome/browser/ui/browser_finder.h" | |
15 #include "chrome/browser/ui/browser_window.h" | |
16 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
17 #include "chrome/common/extensions/api/extension_options_internal.h" | |
18 #include "components/crx_file/id_util.h" | |
19 #include "components/renderer_context_menu/context_menu_delegate.h" | |
20 #include "content/public/browser/render_process_host.h" | |
21 #include "content/public/browser/site_instance.h" | |
22 #include "content/public/browser/web_contents.h" | |
23 #include "extensions/browser/extension_function_dispatcher.h" | |
24 #include "extensions/browser/extension_registry.h" | |
25 #include "extensions/browser/guest_view/guest_view_manager.h" | |
26 #include "extensions/common/constants.h" | |
27 #include "extensions/common/extension.h" | |
28 #include "extensions/common/extension_messages.h" | |
29 #include "extensions/common/feature_switch.h" | |
30 #include "extensions/common/manifest_handlers/options_page_info.h" | |
31 #include "extensions/common/permissions/permissions_data.h" | |
32 #include "extensions/strings/grit/extensions_strings.h" | |
33 #include "ipc/ipc_message_macros.h" | |
34 | |
35 using content::WebContents; | |
36 using namespace extensions::api; | |
37 | |
38 // static | |
39 const char ExtensionOptionsGuest::Type[] = "extensionoptions"; | |
40 | |
41 ExtensionOptionsGuest::ExtensionOptionsGuest( | |
42 content::BrowserContext* browser_context, | |
43 int guest_instance_id) | |
44 : GuestView<ExtensionOptionsGuest>(browser_context, guest_instance_id) { | |
45 } | |
46 | |
47 ExtensionOptionsGuest::~ExtensionOptionsGuest() { | |
48 } | |
49 | |
50 // static | |
51 extensions::GuestViewBase* ExtensionOptionsGuest::Create( | |
52 content::BrowserContext* browser_context, | |
53 int guest_instance_id) { | |
54 if (!extensions::FeatureSwitch::embedded_extension_options()->IsEnabled()) { | |
55 return NULL; | |
56 } | |
57 return new ExtensionOptionsGuest(browser_context, guest_instance_id); | |
58 } | |
59 | |
60 void ExtensionOptionsGuest::CreateWebContents( | |
61 const std::string& embedder_extension_id, | |
62 int embedder_render_process_id, | |
63 const base::DictionaryValue& create_params, | |
64 const WebContentsCreatedCallback& callback) { | |
65 // Get the extension's base URL. | |
66 std::string extension_id; | |
67 create_params.GetString(extensionoptions::kExtensionId, &extension_id); | |
68 | |
69 if (!crx_file::id_util::IdIsValid(extension_id)) { | |
70 callback.Run(NULL); | |
71 return; | |
72 } | |
73 | |
74 if (crx_file::id_util::IdIsValid(embedder_extension_id) && | |
75 extension_id != embedder_extension_id) { | |
76 // Extensions cannot embed other extensions' options pages. | |
77 callback.Run(NULL); | |
78 return; | |
79 } | |
80 | |
81 GURL extension_url = | |
82 extensions::Extension::GetBaseURLFromExtensionId(extension_id); | |
83 if (!extension_url.is_valid()) { | |
84 callback.Run(NULL); | |
85 return; | |
86 } | |
87 | |
88 // Get the options page URL for later use. | |
89 extensions::ExtensionRegistry* registry = | |
90 extensions::ExtensionRegistry::Get(browser_context()); | |
91 const extensions::Extension* extension = | |
92 registry->enabled_extensions().GetByID(extension_id); | |
93 options_page_ = extensions::OptionsPageInfo::GetOptionsPage(extension); | |
94 if (!options_page_.is_valid()) { | |
95 callback.Run(NULL); | |
96 return; | |
97 } | |
98 | |
99 // Create a WebContents using the extension URL. The options page's | |
100 // WebContents should live in the same process as its parent extension's | |
101 // WebContents, so we can use |extension_url| for creating the SiteInstance. | |
102 content::SiteInstance* options_site_instance = | |
103 content::SiteInstance::CreateForURL(browser_context(), extension_url); | |
104 WebContents::CreateParams params(browser_context(), options_site_instance); | |
105 params.guest_delegate = this; | |
106 callback.Run(WebContents::Create(params)); | |
107 } | |
108 | |
109 void ExtensionOptionsGuest::DidAttachToEmbedder() { | |
110 SetUpAutoSize(); | |
111 web_contents()->GetController().LoadURL(options_page_, | |
112 content::Referrer(), | |
113 content::PAGE_TRANSITION_LINK, | |
114 std::string()); | |
115 } | |
116 | |
117 void ExtensionOptionsGuest::DidInitialize() { | |
118 extension_function_dispatcher_.reset( | |
119 new extensions::ExtensionFunctionDispatcher(browser_context(), this)); | |
120 extensions::ChromeExtensionWebContentsObserver::CreateForWebContents( | |
121 web_contents()); | |
122 } | |
123 | |
124 void ExtensionOptionsGuest::DidStopLoading() { | |
125 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
126 DispatchEventToEmbedder(new extensions::GuestViewBase::Event( | |
127 extensions::api::extension_options_internal::OnLoad::kEventName, | |
128 args.Pass())); | |
129 } | |
130 | |
131 const char* ExtensionOptionsGuest::GetAPINamespace() const { | |
132 return extensionoptions::kAPINamespace; | |
133 } | |
134 | |
135 int ExtensionOptionsGuest::GetTaskPrefix() const { | |
136 return IDS_EXTENSION_TASK_MANAGER_EXTENSIONOPTIONS_TAG_PREFIX; | |
137 } | |
138 | |
139 void ExtensionOptionsGuest::GuestSizeChangedDueToAutoSize( | |
140 const gfx::Size& old_size, | |
141 const gfx::Size& new_size) { | |
142 scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue()); | |
143 args->SetInteger(extensionoptions::kNewWidth, new_size.width()); | |
144 args->SetInteger(extensionoptions::kNewHeight, new_size.height()); | |
145 args->SetInteger(extensionoptions::kOldWidth, old_size.width()); | |
146 args->SetInteger(extensionoptions::kOldHeight, old_size.height()); | |
147 DispatchEventToEmbedder(new extensions::GuestViewBase::Event( | |
148 extension_options_internal::OnSizeChanged::kEventName, args.Pass())); | |
149 } | |
150 | |
151 bool ExtensionOptionsGuest::IsAutoSizeSupported() const { | |
152 return true; | |
153 } | |
154 | |
155 content::WebContents* ExtensionOptionsGuest::GetAssociatedWebContents() const { | |
156 return web_contents(); | |
157 } | |
158 | |
159 content::WebContents* ExtensionOptionsGuest::OpenURLFromTab( | |
160 content::WebContents* source, | |
161 const content::OpenURLParams& params) { | |
162 Browser* browser = | |
163 chrome::FindBrowserWithWebContents(embedder_web_contents()); | |
164 | |
165 // Don't allow external URLs with the CURRENT_TAB disposition be opened in | |
166 // this guest view, change the disposition to NEW_FOREGROUND_TAB. | |
167 if ((!params.url.SchemeIs(extensions::kExtensionScheme) || | |
168 params.url.host() != options_page_.host()) && | |
169 params.disposition == CURRENT_TAB) { | |
170 return browser->OpenURL( | |
171 content::OpenURLParams(params.url, | |
172 params.referrer, | |
173 params.frame_tree_node_id, | |
174 NEW_FOREGROUND_TAB, | |
175 params.transition, | |
176 params.is_renderer_initiated)); | |
177 } | |
178 return browser->OpenURL(params); | |
179 } | |
180 | |
181 void ExtensionOptionsGuest::CloseContents(content::WebContents* source) { | |
182 DispatchEventToEmbedder(new extensions::GuestViewBase::Event( | |
183 extension_options_internal::OnClose::kEventName, | |
184 make_scoped_ptr(new base::DictionaryValue()))); | |
185 } | |
186 | |
187 bool ExtensionOptionsGuest::HandleContextMenu( | |
188 const content::ContextMenuParams& params) { | |
189 ContextMenuDelegate* menu_delegate = | |
190 ContextMenuDelegate::FromWebContents(web_contents()); | |
191 DCHECK(menu_delegate); | |
192 | |
193 scoped_ptr<RenderViewContextMenu> menu = | |
194 menu_delegate->BuildMenu(web_contents(), params); | |
195 menu_delegate->ShowMenu(menu.Pass()); | |
196 return true; | |
197 } | |
198 | |
199 bool ExtensionOptionsGuest::ShouldCreateWebContents( | |
200 content::WebContents* web_contents, | |
201 int route_id, | |
202 WindowContainerType window_container_type, | |
203 const base::string16& frame_name, | |
204 const GURL& target_url, | |
205 const std::string& partition_id, | |
206 content::SessionStorageNamespace* session_storage_namespace) { | |
207 // This method handles opening links from within the guest. Since this guest | |
208 // view is used for displaying embedded extension options, we want any | |
209 // external links to be opened in a new tab, not in a new guest view. | |
210 // Therefore we just open the URL in a new tab, and since we aren't handling | |
211 // the new web contents, we return false. | |
212 Browser* browser = | |
213 chrome::FindBrowserWithWebContents(embedder_web_contents()); | |
214 content::OpenURLParams params(target_url, | |
215 content::Referrer(), | |
216 NEW_FOREGROUND_TAB, | |
217 content::PAGE_TRANSITION_LINK, | |
218 false); | |
219 browser->OpenURL(params); | |
220 // TODO(ericzeng): Open the tab in the background if the click was a | |
221 // ctrl-click or middle mouse button click | |
222 return false; | |
223 } | |
224 | |
225 bool ExtensionOptionsGuest::OnMessageReceived(const IPC::Message& message) { | |
226 bool handled = true; | |
227 IPC_BEGIN_MESSAGE_MAP(ExtensionOptionsGuest, message) | |
228 IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) | |
229 IPC_MESSAGE_UNHANDLED(handled = false) | |
230 IPC_END_MESSAGE_MAP() | |
231 return handled; | |
232 } | |
233 | |
234 void ExtensionOptionsGuest::OnRequest( | |
235 const ExtensionHostMsg_Request_Params& params) { | |
236 extension_function_dispatcher_->Dispatch( | |
237 params, web_contents()->GetRenderViewHost()); | |
238 } | |
239 | |
240 void ExtensionOptionsGuest::SetUpAutoSize() { | |
241 // Read the autosize parameters passed in from the embedder. | |
242 bool auto_size_enabled = false; | |
243 attach_params()->GetBoolean(extensionoptions::kAttributeAutoSize, | |
244 &auto_size_enabled); | |
245 | |
246 int max_height = 0; | |
247 int max_width = 0; | |
248 attach_params()->GetInteger(extensionoptions::kAttributeMaxHeight, | |
249 &max_height); | |
250 attach_params()->GetInteger(extensionoptions::kAttributeMaxWidth, &max_width); | |
251 | |
252 int min_height = 0; | |
253 int min_width = 0; | |
254 attach_params()->GetInteger(extensionoptions::kAttributeMinHeight, | |
255 &min_height); | |
256 attach_params()->GetInteger(extensionoptions::kAttributeMinWidth, &min_width); | |
257 | |
258 // Call SetAutoSize to apply all the appropriate validation and clipping of | |
259 // values. | |
260 SetAutoSize(auto_size_enabled, | |
261 gfx::Size(min_width, min_height), | |
262 gfx::Size(max_width, max_height)); | |
263 } | |
OLD | NEW |