Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / extensions / browser / guest_view / extension_options / extension_options_guest.cc
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/extension_options/extension_options_guest.h"
6
7 #include "base/values.h"
8 #include "components/crx_file/id_util.h"
9 #include "content/public/browser/render_process_host.h"
10 #include "content/public/browser/site_instance.h"
11 #include "content/public/browser/web_contents.h"
12 #include "extensions/browser/api/extensions_api_client.h"
13 #include "extensions/browser/extension_function_dispatcher.h"
14 #include "extensions/browser/extension_registry.h"
15 #include "extensions/browser/extension_web_contents_observer.h"
16 #include "extensions/browser/guest_view/extension_options/extension_options_constants.h"
17 #include "extensions/browser/guest_view/extension_options/extension_options_guest_delegate.h"
18 #include "extensions/browser/guest_view/guest_view_manager.h"
19 #include "extensions/common/api/extension_options_internal.h"
20 #include "extensions/common/constants.h"
21 #include "extensions/common/extension.h"
22 #include "extensions/common/extension_messages.h"
23 #include "extensions/common/feature_switch.h"
24 #include "extensions/common/manifest_handlers/options_page_info.h"
25 #include "extensions/common/permissions/permissions_data.h"
26 #include "extensions/strings/grit/extensions_strings.h"
27 #include "ipc/ipc_message_macros.h"
28
29 using content::WebContents;
30 using namespace extensions::core_api;
31
32 namespace extensions {
33
34 // static
35 const char ExtensionOptionsGuest::Type[] = "extensionoptions";
36
37 ExtensionOptionsGuest::ExtensionOptionsGuest(
38     content::BrowserContext* browser_context,
39     int guest_instance_id)
40     : GuestView<ExtensionOptionsGuest>(browser_context, guest_instance_id),
41       extension_options_guest_delegate_(
42           extensions::ExtensionsAPIClient::Get()
43               ->CreateExtensionOptionsGuestDelegate(this)) {
44 }
45
46 ExtensionOptionsGuest::~ExtensionOptionsGuest() {
47 }
48
49 // static
50 extensions::GuestViewBase* ExtensionOptionsGuest::Create(
51     content::BrowserContext* browser_context,
52     int guest_instance_id) {
53   if (!extensions::FeatureSwitch::embedded_extension_options()->IsEnabled()) {
54     return NULL;
55   }
56   return new ExtensionOptionsGuest(browser_context, guest_instance_id);
57 }
58
59 void ExtensionOptionsGuest::CreateWebContents(
60     const std::string& embedder_extension_id,
61     int embedder_render_process_id,
62     const GURL& embedder_site_url,
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                                           ui::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   if (extension_options_guest_delegate_) {
121     extension_options_guest_delegate_->DidInitialize();
122   }
123 }
124
125 void ExtensionOptionsGuest::DidStopLoading() {
126   scoped_ptr<base::DictionaryValue> args(new base::DictionaryValue());
127   DispatchEventToEmbedder(new extensions::GuestViewBase::Event(
128       extension_options_internal::OnLoad::kEventName, 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   if (!extension_options_guest_delegate_)
163     return NULL;
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 extension_options_guest_delegate_->OpenURLInNewTab(
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 extension_options_guest_delegate_->OpenURLInNewTab(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   if (!extension_options_guest_delegate_)
190     return false;
191
192   return extension_options_guest_delegate_->HandleContextMenu(params);
193 }
194
195 bool ExtensionOptionsGuest::ShouldCreateWebContents(
196     content::WebContents* web_contents,
197     int route_id,
198     WindowContainerType window_container_type,
199     const base::string16& frame_name,
200     const GURL& target_url,
201     const std::string& partition_id,
202     content::SessionStorageNamespace* session_storage_namespace) {
203   // This method handles opening links from within the guest. Since this guest
204   // view is used for displaying embedded extension options, we want any
205   // external links to be opened in a new tab, not in a new guest view.
206   // Therefore we just open the URL in a new tab, and since we aren't handling
207   // the new web contents, we return false.
208   // TODO(ericzeng): Open the tab in the background if the click was a
209   //   ctrl-click or middle mouse button click
210   if (extension_options_guest_delegate_) {
211     extension_options_guest_delegate_->OpenURLInNewTab(
212         content::OpenURLParams(target_url,
213                                content::Referrer(),
214                                NEW_FOREGROUND_TAB,
215                                ui::PAGE_TRANSITION_LINK,
216                                false));
217   }
218   return false;
219 }
220
221 bool ExtensionOptionsGuest::OnMessageReceived(const IPC::Message& message) {
222   bool handled = true;
223   IPC_BEGIN_MESSAGE_MAP(ExtensionOptionsGuest, message)
224     IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest)
225     IPC_MESSAGE_UNHANDLED(handled = false)
226   IPC_END_MESSAGE_MAP()
227   return handled;
228 }
229
230 void ExtensionOptionsGuest::OnRequest(
231     const ExtensionHostMsg_Request_Params& params) {
232   extension_function_dispatcher_->Dispatch(params,
233                                            web_contents()->GetRenderViewHost());
234 }
235
236 void ExtensionOptionsGuest::SetUpAutoSize() {
237   // Read the autosize parameters passed in from the embedder.
238   bool auto_size_enabled = false;
239   attach_params()->GetBoolean(extensionoptions::kAttributeAutoSize,
240                               &auto_size_enabled);
241
242   int max_height = 0;
243   int max_width = 0;
244   attach_params()->GetInteger(extensionoptions::kAttributeMaxHeight,
245                               &max_height);
246   attach_params()->GetInteger(extensionoptions::kAttributeMaxWidth, &max_width);
247
248   int min_height = 0;
249   int min_width = 0;
250   attach_params()->GetInteger(extensionoptions::kAttributeMinHeight,
251                               &min_height);
252   attach_params()->GetInteger(extensionoptions::kAttributeMinWidth, &min_width);
253
254   // Call SetAutoSize to apply all the appropriate validation and clipping of
255   // values.
256   SetAutoSize(auto_size_enabled,
257               gfx::Size(min_width, min_height),
258               gfx::Size(max_width, max_height));
259 }
260
261 }  // namespace extensions