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.
5 // Ugly but effective hack to access WebContentsImpl internals.
6 #define private protected
7 #include "content/browser/web_contents/web_contents_impl.h"
10 #include "content/browser/web_contents/web_contents_impl_efl.h"
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"
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
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
37 // * WebContentsImplEfl::HandleNewWebContentsCreate - Create new WebContents
39 // The execution of parts 2 and 3 is controlled by the user of the API through
40 // WebContentsDelegate ShouldCreateWebContentsAsync and WebContentsCreatedAsync
43 // In case WebContentsDelegate returns false from ShouldCreateWebContentsAsync
44 // and WebContentsCreateAsync functions the call sequence is:
46 // + WebContentsImplEfl::CreateMewWimdow
47 // |-+ WebContentsImplEfl::HandleNewWindowRequesst
48 // |-+ WebContentsImplEfl::HandleNewWebContentsCreate
50 // All functions are called in a single sequence.
52 // In the oposite case, both ShouldCreateWebContentsAsync and WebContentsCreateAsyns
55 // + WebContents::Impl::CreateNewWindow
57 // + WebContentsDelegate::WebContentsCreateCallback
58 // |-+ WebContentsImplEfl::HandleNewWindowRequest
60 // + WebContentsDelegate::WebContentsCreateAsync
61 // |-+ WebContentsImplEfl::HandleNewWebContentsCreate
63 // In this case the user of the API decides when to execute each stage of the
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;
78 WebContentsImplEfl::WebContentsImplEfl(BrowserContext* browser_context,
80 : WebContentsImpl(browser_context)
81 , platform_data_(platform_data) {
84 void WebContentsImplEfl::SetEflDelegate(WebContentsEflDelegate* delegate) {
85 efl_delegate_.reset(delegate);
88 WebContents* WebContentsImplEfl::Clone() {
89 NOTREACHED() << "Cloning WebContents is not supported in EFL port";
93 void WebContentsImplEfl::SetUserAgentOverride(const std::string& override) {
94 if (GetUserAgentOverride() == override)
97 renderer_preferences_.user_agent_override = override;
99 // Send the new override string to the renderer.
100 RenderViewHost* host = GetRenderViewHost();
102 host->SyncRendererPrefs();
104 // In chromium upstream, page is reloaded if a load is currently in progress.
105 // In chromium-efl port, the behaviour is different.
107 FOR_EACH_OBSERVER(WebContentsObserver, observers_,
108 UserAgentOverrideSet(override));
111 void WebContentsImplEfl::CreateNewWindow(
112 SiteInstance* source_site_instance,
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);
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
126 DCHECK(!params.opener_suppressed || route_id == MSG_ROUTING_NONE);
128 scoped_refptr<SiteInstance> site_instance =
129 params.opener_suppressed && !is_guest ?
130 SiteInstance::CreateForURL(GetBrowserContext(), params.target_url) :
131 source_site_instance;
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;
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) {
145 base::UserMetricsAction("Terminate_ProcessMismatch_CreateNewWindow"));
146 rph->Shutdown(RESULT_CODE_KILLED, false);
151 // We must assign the SessionStorageNamespace before calling Init().
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));
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);
173 efl_delegate_->ShouldCreateWebContentsAsync(callback, params.target_url))
175 // End of EFL port specific code.
177 content::WebContents* thiz = this;
179 !delegate_->ShouldCreateWebContents(thiz,
182 params.window_container_type,
186 session_storage_namespace)) {
187 CancelWindowRequest(render_process_id, route_id, main_frame_route_id);
191 // Added for EFL implementation of WebContentsImp. In non EFL version
192 // contents of HandleNewWebContentsCreate would come here.
196 void WebContentsImplEfl::CancelWindowRequest(
197 int render_process_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));
206 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(route_id);
207 GetRenderViewHost()->GetProcess()->ResumeRequestsForView(
208 main_frame_route_id);
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,
216 int main_frame_route_id,
217 const ViewHostMsg_CreateWindow_Params& params,
218 SessionStorageNamespace* session_storage_namespace,
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))
232 CancelWindowRequest(render_process_id, route_id, main_frame_route_id);
236 WebContents* WebContentsImplEfl::HandleNewWebContentsCreate(
237 int render_process_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) :
248 const std::string& partition_id =
249 GetContentClient()->browser()->
250 GetStoragePartitionIdForSite(GetBrowserContext(),
251 site_instance->GetSiteURL());
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;
264 WebContentsImplEfl* new_contents = NULL;
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);
272 new_contents = static_cast<WebContentsImplEfl*>(
273 GetBrowserPluginGuest()->CreateNewGuestWindow(create_params));
275 new_contents->GetController().SetSessionStorageNamespace(
277 session_storage_namespace);
278 new_contents->RenderViewCreated(new_contents->GetRenderViewHost());
280 // Added for EFL port
281 new_contents->platform_data_ = platform_data;
283 efl_delegate_->SetUpSmartObject(platform_data, new_contents->GetNativeView());
284 // End of EFL port specific code.
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) {
290 WebContentsView* new_view = new_contents->view_.get();
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);
296 // Save the created window associated with the route so we can show it
298 DCHECK_NE(MSG_ROUTING_NONE, route_id);
299 pending_contents_[route_id] = new_contents;
300 AddDestructionObserver(new_contents);
304 delegate_->WebContentsCreated(
305 this, params.opener_render_frame_id, params.frame_name,
306 params.target_url, new_contents);
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;
314 gfx::Rect initial_pos;
315 delegate_->AddNewContents(
316 this, new_contents, params.disposition, initial_pos,
317 params.user_gesture, &was_blocked);
320 OpenURLParams open_params(params.target_url,
323 ui::PAGE_TRANSITION_LINK,
324 true /* is_renderer_initiated */);
325 open_params.user_gesture = params.user_gesture;
326 new_contents->OpenURL(open_params);