[M47_2526] Chromium upversion to m47_2526 branch
[platform/framework/web/chromium-efl.git] / tizen_src / chromium_impl / content / browser / web_contents / web_contents_impl_efl.cc
1 // Copyright (c) 2014-2015 Samsung Electronics. 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 // Ugly but effective hack to access WebContentsImpl internals.
6 #define private protected
7 #include "content/browser/web_contents/web_contents_impl.h"
8 #undef private
9
10 #include "content/browser/web_contents/web_contents_impl_efl.h"
11
12 #include "content/public/common/content_client.h"
13 #include "content/common/view_messages.h"
14 #include "content/browser/browser_plugin/browser_plugin_guest.h"
15 #include "content/browser/dom_storage/dom_storage_context_wrapper.h"
16 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
17 #include "content/browser/renderer_host/render_view_host_impl.h"
18 #include "content/browser/web_contents/web_contents_view.h"
19 #include "content/public/browser/browser_context.h"
20 #include "content/public/browser/browser_plugin_guest_manager.h"
21 #include "content/public/browser/content_browser_client.h"
22 #include "content/public/browser/storage_partition.h"
23 #include "content/public/browser/user_metrics.h"
24 #include "content/public/browser/web_contents_delegate.h"
25 #include "content/public/browser/web_contents_efl_delegate.h"
26 #include "content/public/common/result_codes.h"
27
28 // Majority of the code in this file was taken directly from
29 // WebContentsImpl::CreateNewWindow. Compared to the original, the function
30 // was split into 3 major parts which can be executed independently. The
31 // parts are:
32 // * WebContentsImplEfl::CreateNewWindow - Handle parts until the actual
33 //   decision regarding if the window should be created or not.
34 // * WebContentsImplEfl::HandleNewWindowRequest - Handle positive/negative
35 //   decision regarding the window. Either continue processing the request or
36 //   cancel it.
37 // * WebContentsImplEfl::HandleNewWebContentsCreate - Create new WebContents
38 //
39 // The execution of parts 2 and 3 is controlled by the user of the API through
40 // WebContentsDelegate ShouldCreateWebContentsAsync and WebContentsCreatedAsync
41 // functions.
42 //
43 // In case WebContentsDelegate returns false from ShouldCreateWebContentsAsync
44 // and WebContentsCreateAsync functions the call sequence is:
45 //
46 // + WebContentsImplEfl::CreateMewWimdow
47 // |-+ WebContentsImplEfl::HandleNewWindowRequesst
48 //   |-+ WebContentsImplEfl::HandleNewWebContentsCreate
49 //
50 // All functions are called in a single sequence.
51 //
52 // In the oposite case, both ShouldCreateWebContentsAsync and WebContentsCreateAsyns
53 // return true:
54 //
55 // + WebContents::Impl::CreateNewWindow
56 // ...
57 // + WebContentsDelegate::WebContentsCreateCallback
58 // |-+ WebContentsImplEfl::HandleNewWindowRequest
59 // ...
60 // + WebContentsDelegate::WebContentsCreateAsync
61 // |-+ WebContentsImplEfl::HandleNewWebContentsCreate
62 //
63 // In this case the user of the API decides when to execute each stage of the
64 // sequence.
65
66 namespace content {
67
68 bool FindMatchingProcess(int render_process_id,
69                          bool* did_match_process,
70                          FrameTreeNode* node) {
71   if (node->current_frame_host()->GetProcess()->GetID() == render_process_id) {
72     *did_match_process = true;
73     return false;
74   }
75   return true;
76 }
77
78 WebContentsImplEfl::WebContentsImplEfl(BrowserContext* browser_context,
79                                        void* platform_data)
80     : WebContentsImpl(browser_context)
81     , platform_data_(platform_data) {
82 }
83
84 void WebContentsImplEfl::SetEflDelegate(WebContentsEflDelegate* delegate) {
85   efl_delegate_.reset(delegate);
86 }
87
88 WebContents* WebContentsImplEfl::Clone() {
89   NOTREACHED() << "Cloning WebContents is not supported in EFL port";
90   return NULL;
91 }
92
93 void WebContentsImplEfl::SetUserAgentOverride(const std::string& override) {
94   if (GetUserAgentOverride() == override)
95     return;
96
97   renderer_preferences_.user_agent_override = override;
98
99   // Send the new override string to the renderer.
100   RenderViewHost* host = GetRenderViewHost();
101   if (host)
102     host->SyncRendererPrefs();
103
104   // In chromium upstream, page is reloaded if a load is currently in progress.
105   // In chromium-efl port, the behaviour is different.
106
107   FOR_EACH_OBSERVER(WebContentsObserver, observers_,
108                     UserAgentOverrideSet(override));
109 }
110
111 void WebContentsImplEfl::CreateNewWindow(
112     SiteInstance* source_site_instance,
113     int route_id,
114     int main_frame_route_id,
115     const ViewHostMsg_CreateWindow_Params& params,
116     SessionStorageNamespace* session_storage_namespace) {
117   // We usually create the new window in the same BrowsingInstance (group of
118   // script-related windows), by passing in the current SiteInstance.  However,
119   // if the opener is being suppressed (in a non-guest), we create a new
120   // SiteInstance in its own BrowsingInstance.
121   bool is_guest = BrowserPluginGuest::IsGuest(this);
122
123   // If the opener is to be suppressed, the new window can be in any process.
124   // Since routing ids are process specific, we must not have one passed in
125   // as argument here.
126   DCHECK(!params.opener_suppressed || route_id == MSG_ROUTING_NONE);
127
128   scoped_refptr<SiteInstance> site_instance =
129       params.opener_suppressed && !is_guest ?
130       SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) :
131       source_site_instance;
132
133   // A message to create a new window can only come from the active process for
134   // this WebContentsImpl instance. If any other process sends the request,
135   // it is invalid and the process must be terminated.
136   int render_process_id = source_site_instance->GetProcess()->GetID();
137   bool did_match_process = false;
138   frame_tree_.ForEach(
139       base::Bind(&FindMatchingProcess, render_process_id, &did_match_process));
140   if (!did_match_process) {
141     RenderProcessHost* rph = source_site_instance->GetProcess();
142     base::ProcessHandle process_handle = rph->GetHandle();
143     if (process_handle != base::kNullProcessHandle) {
144       RecordAction(
145           base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow"));
146       rph->Shutdown(RESULT_CODE_KILLED, false);
147     }
148     return;
149   }
150
151   // We must assign the SessionStorageNamespace before calling Init().
152   //
153   // http://crbug.com/142685
154   const std::string& partition_id =
155       GetContentClient()->browser()->
156           GetStoragePartitionIdForSite(GetBrowserContext(),
157                                        site_instance->GetSiteURL());
158   StoragePartition* partition = BrowserContext::GetStoragePartition(
159       GetBrowserContext(), site_instance.get());
160   DOMStorageContextWrapper* dom_storage_context =
161       static_cast<DOMStorageContextWrapper*>(partition->GetDOMStorageContext());
162   SessionStorageNamespaceImpl* session_storage_namespace_impl =
163       static_cast<SessionStorageNamespaceImpl*>(session_storage_namespace);
164   CHECK(session_storage_namespace_impl->IsFromContext(dom_storage_context));
165
166   // Added for EFL implementation
167   scoped_refptr<SessionStorageNamespace> ssn = session_storage_namespace;
168   base::Callback<void(bool)> callback = base::Bind(
169       &WebContentsImplEfl::HandleNewWindowRequest,
170       base::Unretained(this), render_process_id, route_id,
171       main_frame_route_id, params, ssn);
172   if (efl_delegate_ &&
173       efl_delegate_->ShouldCreateWebContentsAsync(callback, params.target_url))
174     return;
175   // End of EFL port specific code.
176
177   content::WebContents* thiz = this;
178   if (delegate_ &&
179       !delegate_->ShouldCreateWebContents(thiz,
180                                           route_id,
181                                           main_frame_route_id,
182                                           params.window_container_type,
183                                           params.frame_name,
184                                           params.target_url,
185                                           partition_id,
186                                           session_storage_namespace)) {
187     CancelWindowRequest(render_process_id, route_id, main_frame_route_id);
188     return;
189   }
190
191   // Added for EFL implementation of WebContentsImp. In non EFL version
192   // contents of HandleNewWebContentsCreate would come here.
193   callback.Run(true);
194 }
195
196 void WebContentsImplEfl::CancelWindowRequest(
197     int render_process_id,
198     int route_id,
199     int main_frame_route_id) {
200   if (route_id != MSG_ROUTING_NONE &&
201       !RenderViewHost::FromID(render_process_id, route_id)) {
202     // If the embedder didn't create a WebContents for this route, we need to
203     // delete the RenderView that had already been created.
204     Send(new ViewMsg_Close(route_id));
205   }
206   GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
207   GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
208       main_frame_route_id);
209 }
210
211 // This function does not exist in WebContentsImpl. The decision regarding
212 // new WebContents request is always made synchronously.
213 void WebContentsImplEfl::HandleNewWindowRequest(
214     int render_process_id,
215     int route_id,
216     int main_frame_route_id,
217     const ViewHostMsg_CreateWindow_Params& params,
218     SessionStorageNamespace* session_storage_namespace,
219     bool create) {
220
221   if (create) {
222     scoped_refptr<SessionStorageNamespace> ssn = session_storage_namespace;
223     WebContentsEflDelegate::WebContentsCreateCallback callback = base::Bind(
224         &WebContentsImplEfl::HandleNewWebContentsCreate,
225         base::Unretained(this), render_process_id, route_id,
226         main_frame_route_id, params, ssn);
227     if (efl_delegate_ && efl_delegate_->WebContentsCreateAsync(callback))
228       return;
229
230     callback.Run(NULL);
231   } else {
232     CancelWindowRequest(render_process_id, route_id, main_frame_route_id);
233   }
234 }
235
236 WebContents* WebContentsImplEfl::HandleNewWebContentsCreate(
237     int render_process_id,
238     int route_id,
239     int main_frame_route_id,
240     const ViewHostMsg_CreateWindow_Params& params,
241     SessionStorageNamespace* session_storage_namespace,
242     void* platform_data) {
243   bool is_guest = BrowserPluginGuest::IsGuest(this);
244   scoped_refptr<SiteInstance> site_instance =
245       params.opener_suppressed && !is_guest ?
246       SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) :
247       GetSiteInstance();
248   const std::string& partition_id =
249       GetContentClient()->browser()->
250           GetStoragePartitionIdForSite(GetBrowserContext(),
251                                        site_instance->GetSiteURL());
252
253   // Create the new web contents. This will automatically create the new
254   // WebContentsView. In the future, we may want to create the view separately.
255   CreateParams create_params(GetBrowserContext(), site_instance.get());
256   create_params.routing_id = route_id;
257   create_params.main_frame_routing_id = main_frame_route_id;
258   create_params.opener_render_process_id = render_process_id;
259   create_params.opener_render_frame_id = params.opener_render_frame_id;
260   create_params.opener_suppressed = params.opener_suppressed;
261   if (params.disposition == NEW_BACKGROUND_TAB)
262     create_params.initially_hidden = true;
263
264   WebContentsImplEfl* new_contents = NULL;
265   if (!is_guest) {
266     create_params.context = view_->GetNativeView();
267     create_params.initial_size = GetContainerBounds().size();
268     new_contents = new WebContentsImplEfl(
269         create_params.browser_context, platform_data);
270     new_contents->Init(create_params);
271   }  else {
272     new_contents = static_cast<WebContentsImplEfl*>(
273         GetBrowserPluginGuest()->CreateNewGuestWindow(create_params));
274   }
275   new_contents->GetController().SetSessionStorageNamespace(
276         partition_id,
277         session_storage_namespace);
278   new_contents->RenderViewCreated(new_contents->GetRenderViewHost());
279
280   // Added for EFL port
281   new_contents->platform_data_ = platform_data;
282   if (efl_delegate_)
283       efl_delegate_->SetUpSmartObject(platform_data, new_contents->GetNativeView());
284   // End of EFL port specific code.
285
286   // Save the window for later if we're not suppressing the opener (since it
287   // will be shown immediately).
288   if (!params.opener_suppressed) {
289     if (!is_guest) {
290       WebContentsView* new_view = new_contents->view_.get();
291
292       // TODO(brettw): It seems bogus that we have to call this function on the
293       // newly created object and give it one of its own member variables.
294       new_view->CreateViewForWidget(new_contents->GetRenderViewHost(), false);
295     }
296     // Save the created window associated with the route so we can show it
297     // later.
298     DCHECK_NE(MSG_ROUTING_NONE, route_id);
299     pending_contents_[route_id] = new_contents;
300     AddDestructionObserver(new_contents);
301   }
302
303   if (delegate_) {
304     delegate_->WebContentsCreated(
305         this, params.opener_render_frame_id, params.frame_name,
306         params.target_url, new_contents);
307   }
308
309   if (params.opener_suppressed) {
310     // When the opener is suppressed, the original renderer cannot access the
311     // new window.  As a result, we need to show and navigate the window here.
312     bool was_blocked = false;
313     if (delegate_) {
314       gfx::Rect initial_pos;
315       delegate_->AddNewContents(
316           this, new_contents, params.disposition, initial_pos,
317           params.user_gesture, &was_blocked);
318     }
319     if (!was_blocked) {
320       OpenURLParams open_params(params.target_url,
321                                 Referrer(),
322                                 CURRENT_TAB,
323                                 ui::PAGE_TRANSITION_LINK,
324                                 true /* is_renderer_initiated */);
325       open_params.user_gesture = params.user_gesture;
326       new_contents->OpenURL(open_params);
327     }
328   }
329
330   return new_contents;
331 }
332
333 }