1f88835cd275d8fe60cc96cbc4735ac4ed5025ee
[platform/framework/web/crosswalk.git] / src / content / browser / renderer_host / render_widget_helper.cc
1 // Copyright (c) 2012 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 "content/browser/renderer_host/render_widget_helper.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/lazy_instance.h"
10 #include "base/posix/eintr_wrapper.h"
11 #include "base/threading/thread.h"
12 #include "base/threading/thread_restrictions.h"
13 #include "content/browser/gpu/gpu_process_host_ui_shim.h"
14 #include "content/browser/gpu/gpu_surface_tracker.h"
15 #include "content/browser/loader/resource_dispatcher_host_impl.h"
16 #include "content/browser/renderer_host/render_process_host_impl.h"
17 #include "content/browser/renderer_host/render_view_host_impl.h"
18 #include "content/browser/dom_storage/session_storage_namespace_impl.h"
19 #include "content/common/view_messages.h"
20
21 namespace content {
22 namespace {
23
24 typedef std::map<int, RenderWidgetHelper*> WidgetHelperMap;
25 base::LazyInstance<WidgetHelperMap> g_widget_helpers =
26     LAZY_INSTANCE_INITIALIZER;
27
28 void AddWidgetHelper(int render_process_id,
29                      const scoped_refptr<RenderWidgetHelper>& widget_helper) {
30   DCHECK_CURRENTLY_ON(BrowserThread::IO);
31   // We don't care if RenderWidgetHelpers overwrite an existing process_id. Just
32   // want this to be up to date.
33   g_widget_helpers.Get()[render_process_id] = widget_helper.get();
34 }
35
36 }  // namespace
37
38 RenderWidgetHelper::RenderWidgetHelper()
39     : render_process_id_(-1),
40       resource_dispatcher_host_(NULL) {
41 }
42
43 RenderWidgetHelper::~RenderWidgetHelper() {
44   DCHECK_CURRENTLY_ON(BrowserThread::IO);
45
46   // Delete this RWH from the map if it is found.
47   WidgetHelperMap& widget_map = g_widget_helpers.Get();
48   WidgetHelperMap::iterator it = widget_map.find(render_process_id_);
49   if (it != widget_map.end() && it->second == this)
50     widget_map.erase(it);
51
52 #if defined(OS_POSIX) && !defined(OS_ANDROID)
53   ClearAllocatedDIBs();
54 #endif
55 }
56
57 void RenderWidgetHelper::Init(
58     int render_process_id,
59     ResourceDispatcherHostImpl* resource_dispatcher_host) {
60   render_process_id_ = render_process_id;
61   resource_dispatcher_host_ = resource_dispatcher_host;
62
63   BrowserThread::PostTask(
64       BrowserThread::IO, FROM_HERE,
65       base::Bind(&AddWidgetHelper,
66                  render_process_id_, make_scoped_refptr(this)));
67 }
68
69 int RenderWidgetHelper::GetNextRoutingID() {
70   return next_routing_id_.GetNext() + 1;
71 }
72
73 // static
74 RenderWidgetHelper* RenderWidgetHelper::FromProcessHostID(
75     int render_process_host_id) {
76   DCHECK_CURRENTLY_ON(BrowserThread::IO);
77   WidgetHelperMap::const_iterator ci = g_widget_helpers.Get().find(
78       render_process_host_id);
79   return (ci == g_widget_helpers.Get().end())? NULL : ci->second;
80 }
81
82 void RenderWidgetHelper::ResumeDeferredNavigation(
83     const GlobalRequestID& request_id) {
84   BrowserThread::PostTask(
85       BrowserThread::IO, FROM_HERE,
86       base::Bind(&RenderWidgetHelper::OnResumeDeferredNavigation,
87                  this,
88                  request_id));
89 }
90
91 void RenderWidgetHelper::ResumeResponseDeferredAtStart(
92     const GlobalRequestID& request_id) {
93   BrowserThread::PostTask(
94       BrowserThread::IO,
95       FROM_HERE,
96       base::Bind(&RenderWidgetHelper::OnResumeResponseDeferredAtStart,
97                  this,
98                  request_id));
99 }
100
101 void RenderWidgetHelper::ResumeRequestsForView(int route_id) {
102   // We only need to resume blocked requests if we used a valid route_id.
103   // See CreateNewWindow.
104   if (route_id != MSG_ROUTING_NONE) {
105     BrowserThread::PostTask(
106         BrowserThread::IO, FROM_HERE,
107         base::Bind(&RenderWidgetHelper::OnResumeRequestsForView,
108             this, route_id));
109   }
110 }
111
112 void RenderWidgetHelper::OnResumeDeferredNavigation(
113     const GlobalRequestID& request_id) {
114   resource_dispatcher_host_->ResumeDeferredNavigation(request_id);
115 }
116
117 void RenderWidgetHelper::OnResumeResponseDeferredAtStart(
118     const GlobalRequestID& request_id) {
119   resource_dispatcher_host_->ResumeResponseDeferredAtStart(request_id);
120 }
121
122 void RenderWidgetHelper::CreateNewWindow(
123     const ViewHostMsg_CreateWindow_Params& params,
124     bool no_javascript_access,
125     base::ProcessHandle render_process,
126     int* route_id,
127     int* main_frame_route_id,
128     int* surface_id,
129     SessionStorageNamespace* session_storage_namespace) {
130   if (params.opener_suppressed || no_javascript_access) {
131     // If the opener is supppressed or script access is disallowed, we should
132     // open the window in a new BrowsingInstance, and thus a new process. That
133     // means the current renderer process will not be able to route messages to
134     // it. Because of this, we will immediately show and navigate the window
135     // in OnCreateWindowOnUI, using the params provided here.
136     *route_id = MSG_ROUTING_NONE;
137     *main_frame_route_id = MSG_ROUTING_NONE;
138     *surface_id = 0;
139   } else {
140     *route_id = GetNextRoutingID();
141     *main_frame_route_id = GetNextRoutingID();
142     *surface_id = GpuSurfaceTracker::Get()->AddSurfaceForRenderer(
143         render_process_id_, *route_id);
144     // Block resource requests until the view is created, since the HWND might
145     // be needed if a response ends up creating a plugin.
146     resource_dispatcher_host_->BlockRequestsForRoute(
147         render_process_id_, *route_id);
148     resource_dispatcher_host_->BlockRequestsForRoute(
149         render_process_id_, *main_frame_route_id);
150   }
151
152   BrowserThread::PostTask(
153       BrowserThread::UI, FROM_HERE,
154       base::Bind(&RenderWidgetHelper::OnCreateWindowOnUI,
155                  this, params, *route_id, *main_frame_route_id,
156                  make_scoped_refptr(session_storage_namespace)));
157 }
158
159 void RenderWidgetHelper::OnCreateWindowOnUI(
160     const ViewHostMsg_CreateWindow_Params& params,
161     int route_id,
162     int main_frame_route_id,
163     SessionStorageNamespace* session_storage_namespace) {
164   RenderViewHostImpl* host =
165       RenderViewHostImpl::FromID(render_process_id_, params.opener_id);
166   if (host)
167     host->CreateNewWindow(route_id, main_frame_route_id, params,
168         session_storage_namespace);
169 }
170
171 void RenderWidgetHelper::OnResumeRequestsForView(int route_id) {
172   resource_dispatcher_host_->ResumeBlockedRequestsForRoute(
173       render_process_id_, route_id);
174 }
175
176 void RenderWidgetHelper::CreateNewWidget(int opener_id,
177                                          blink::WebPopupType popup_type,
178                                          int* route_id,
179                                          int* surface_id) {
180   *route_id = GetNextRoutingID();
181   *surface_id = GpuSurfaceTracker::Get()->AddSurfaceForRenderer(
182       render_process_id_, *route_id);
183   BrowserThread::PostTask(
184       BrowserThread::UI, FROM_HERE,
185       base::Bind(
186           &RenderWidgetHelper::OnCreateWidgetOnUI, this, opener_id, *route_id,
187           popup_type));
188 }
189
190 void RenderWidgetHelper::CreateNewFullscreenWidget(int opener_id,
191                                                    int* route_id,
192                                                    int* surface_id) {
193   *route_id = GetNextRoutingID();
194   *surface_id = GpuSurfaceTracker::Get()->AddSurfaceForRenderer(
195       render_process_id_, *route_id);
196   BrowserThread::PostTask(
197       BrowserThread::UI, FROM_HERE,
198       base::Bind(
199           &RenderWidgetHelper::OnCreateFullscreenWidgetOnUI, this,
200           opener_id, *route_id));
201 }
202
203 void RenderWidgetHelper::OnCreateWidgetOnUI(
204     int opener_id, int route_id, blink::WebPopupType popup_type) {
205   RenderViewHostImpl* host = RenderViewHostImpl::FromID(
206       render_process_id_, opener_id);
207   if (host)
208     host->CreateNewWidget(route_id, popup_type);
209 }
210
211 void RenderWidgetHelper::OnCreateFullscreenWidgetOnUI(int opener_id,
212                                                       int route_id) {
213   RenderViewHostImpl* host = RenderViewHostImpl::FromID(
214       render_process_id_, opener_id);
215   if (host)
216     host->CreateNewFullscreenWidget(route_id);
217 }
218
219 #if defined(OS_POSIX) && !defined(OS_ANDROID)
220 void RenderWidgetHelper::AllocTransportDIB(uint32 size,
221                                            bool cache_in_browser,
222                                            TransportDIB::Handle* result) {
223   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
224   if (!shared_memory->CreateAnonymous(size)) {
225     result->fd = -1;
226     result->auto_close = false;
227     return;
228   }
229
230   shared_memory->GiveToProcess(0 /* pid, not needed */, result);
231
232   if (cache_in_browser) {
233     // Keep a copy of the file descriptor around
234     base::AutoLock locked(allocated_dibs_lock_);
235     allocated_dibs_[shared_memory->id()] = dup(result->fd);
236   }
237 }
238
239 void RenderWidgetHelper::FreeTransportDIB(TransportDIB::Id dib_id) {
240   base::AutoLock locked(allocated_dibs_lock_);
241
242   const std::map<TransportDIB::Id, int>::iterator
243     i = allocated_dibs_.find(dib_id);
244
245   if (i != allocated_dibs_.end()) {
246     if (IGNORE_EINTR(close(i->second)) < 0)
247       PLOG(ERROR) << "close";
248     allocated_dibs_.erase(i);
249   } else {
250     DLOG(WARNING) << "Renderer asked us to free unknown transport DIB";
251   }
252 }
253
254 void RenderWidgetHelper::ClearAllocatedDIBs() {
255   for (std::map<TransportDIB::Id, int>::iterator
256        i = allocated_dibs_.begin(); i != allocated_dibs_.end(); ++i) {
257     if (IGNORE_EINTR(close(i->second)) < 0)
258       PLOG(ERROR) << "close: " << i->first;
259   }
260
261   allocated_dibs_.clear();
262 }
263 #endif
264
265 }  // namespace content