summaryrefslogtreecommitdiff
path: root/chromium/content/browser/renderer_host/render_widget_helper.h
blob: c5e80a1a29688decb69df050eea7750f13c63c6c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_
#define CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_

#include <deque>
#include <map>

#include "base/atomic_sequence_num.h"
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "base/process/process.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/content_browser_client.h"
#include "content/public/browser/global_request_id.h"
#include "content/public/common/window_container_type.h"
#include "third_party/WebKit/public/web/WebPopupType.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/surface/transport_dib.h"

namespace IPC {
class Message;
}

namespace base {
class TimeDelta;
}

struct ViewHostMsg_CreateWindow_Params;
struct ViewMsg_SwapOut_Params;

namespace content {
class ResourceDispatcherHostImpl;
class SessionStorageNamespace;

// Instantiated per RenderProcessHost to provide various optimizations on
// behalf of a RenderWidgetHost.  This class bridges between the IO thread
// where the RenderProcessHost's MessageFilter lives and the UI thread where
// the RenderWidgetHost lives.
//
//
// OPTIMIZED RESIZE
//
//   RenderWidgetHelper is used to implement optimized resize.  When the
//   RenderWidgetHost is resized, it sends a Resize message to its RenderWidget
//   counterpart in the renderer process.  In response to the Resize message,
//   the RenderWidget generates a new BackingStore and sends an UpdateRect
//   message (or BuffersSwapped via the GPU process in the case of accelerated
//   compositing), and it sets the IS_RESIZE_ACK flag in the UpdateRect message
//   to true.  In the accelerated case, an UpdateRect is still sent from the
//   renderer to the browser with acks and plugin moves even though the GPU
//   BackingStore was sent earlier in the BuffersSwapped message. "BackingStore
//   message" is used throughout this code and documentation to mean either a
//   software UpdateRect or GPU BuffersSwapped message.
//
//   Back in the browser process, when the RenderProcessHost's MessageFilter
//   sees an UpdateRect message (or when the GpuProcessHost sees a
//   BuffersSwapped message), it directs it to the RenderWidgetHelper by calling
//   the DidReceiveBackingStoreMsg method. That method stores the data for the
//   message in a map, where it can be directly accessed by the RenderWidgetHost
//   on the UI thread during a call to RenderWidgetHost's GetBackingStore
//   method.
//
//   When the RenderWidgetHost's GetBackingStore method is called, it first
//   checks to see if it is waiting for a resize ack.  If it is, then it calls
//   the RenderWidgetHelper's WaitForBackingStoreMsg to check if there is
//   already a resulting BackingStore message (or to wait a short amount of time
//   for one to arrive).  The main goal of this mechanism is to short-cut the
//   usual way in which IPC messages are proxied over to the UI thread via
//   InvokeLater. This approach is necessary since window resize is followed up
//   immediately by a request to repaint the window.
//
//
// OPTIMIZED TAB SWITCHING
//
//   When a RenderWidgetHost is in a background tab, it is flagged as hidden.
//   This causes the corresponding RenderWidget to stop sending BackingStore
//   messages. The RenderWidgetHost also discards its backingstore when it is
//   hidden, which helps free up memory.  As a result, when a RenderWidgetHost
//   is restored, it can be momentarily be without a backingstore.  (Restoring
//   a RenderWidgetHost results in a WasShown message being sent to the
//   RenderWidget, which triggers a full BackingStore message.)  This can lead
//   to an observed rendering glitch as the WebContentsImpl will just have to
//   fill white overtop the RenderWidgetHost until the RenderWidgetHost
//   receives a BackingStore message to refresh its backingstore.
//
//   To avoid this 'white flash', the RenderWidgetHost again makes use of the
//   RenderWidgetHelper's WaitForBackingStoreMsg method.  When the
//   RenderWidgetHost's GetBackingStore method is called, it will call
//   WaitForBackingStoreMsg if it has no backingstore.
//
// TRANSPORT DIB CREATION
//
//   On some platforms (currently the Mac) the renderer cannot create transport
//   DIBs because of sandbox limitations. Thus, it has to make synchronous IPCs
//   to the browser for them. Since these requests are synchronous, they cannot
//   terminate on the UI thread. Thus, in this case, this object performs the
//   allocation and maintains the set of allocated transport DIBs which the
//   renderers can refer to.
//
class RenderWidgetHelper
    : public base::RefCountedThreadSafe<RenderWidgetHelper,
                                        BrowserThread::DeleteOnIOThread> {
 public:
  RenderWidgetHelper();

  void Init(int render_process_id,
            ResourceDispatcherHostImpl* resource_dispatcher_host);

  // Gets the next available routing id.  This is thread safe.
  int GetNextRoutingID();

  // IO THREAD ONLY -----------------------------------------------------------

  // Lookup the RenderWidgetHelper from the render_process_host_id. Returns NULL
  // if not found. NOTE: The raw pointer is for temporary use only. To retain,
  // store in a scoped_refptr.
  static RenderWidgetHelper* FromProcessHostID(int render_process_host_id);

  // UI THREAD ONLY -----------------------------------------------------------

  // These three functions provide the backend implementation of the
  // corresponding functions in RenderProcessHost. See those declarations
  // for documentation.
  void ResumeDeferredNavigation(const GlobalRequestID& request_id);
  bool WaitForBackingStoreMsg(int render_widget_id,
                              const base::TimeDelta& max_delay,
                              IPC::Message* msg);
  // Called to resume the requests for a view after it's ready. The view was
  // created by CreateNewWindow which initially blocked the requests.
  void ResumeRequestsForView(int route_id);

#if defined(OS_POSIX) && !defined(TOOLKIT_GTK) && !defined(OS_ANDROID)
  // Given the id of a transport DIB, return a mapping to it or NULL on error.
  TransportDIB* MapTransportDIB(TransportDIB::Id dib_id);
#endif

  // IO THREAD ONLY -----------------------------------------------------------

  // Called on the IO thread when a BackingStore message is received.
  void DidReceiveBackingStoreMsg(const IPC::Message& msg);

  void CreateNewWindow(
      const ViewHostMsg_CreateWindow_Params& params,
      bool no_javascript_access,
      base::ProcessHandle render_process,
      int* route_id,
      int* main_frame_route_id,
      int* surface_id,
      SessionStorageNamespace* session_storage_namespace);
  void CreateNewWidget(int opener_id,
                       WebKit::WebPopupType popup_type,
                       int* route_id,
                       int* surface_id);
  void CreateNewFullscreenWidget(int opener_id, int* route_id, int* surface_id);

#if defined(OS_POSIX)
  // Called on the IO thread to handle the allocation of a TransportDIB.  If
  // |cache_in_browser| is |true|, then a copy of the shmem is kept by the
  // browser, and it is the caller's repsonsibility to call
  // FreeTransportDIB().  In all cases, the caller is responsible for deleting
  // the resulting TransportDIB.
  void AllocTransportDIB(uint32 size,
                         bool cache_in_browser,
                         TransportDIB::Handle* result);

  // Called on the IO thread to handle the freeing of a transport DIB
  void FreeTransportDIB(TransportDIB::Id dib_id);
#endif

 private:
  // A class used to proxy a paint message.  PaintMsgProxy objects are created
  // on the IO thread and destroyed on the UI thread.
  class BackingStoreMsgProxy;
  friend class BackingStoreMsgProxy;
  friend class base::RefCountedThreadSafe<RenderWidgetHelper>;
  friend struct BrowserThread::DeleteOnThread<BrowserThread::IO>;
  friend class base::DeleteHelper<RenderWidgetHelper>;

  typedef std::deque<BackingStoreMsgProxy*> BackingStoreMsgProxyQueue;
  // Map from render_widget_id to a queue of live PaintMsgProxy instances.
  typedef base::hash_map<int, BackingStoreMsgProxyQueue >
      BackingStoreMsgProxyMap;

  ~RenderWidgetHelper();

  // Called on the UI thread to discard a paint message.
  void OnDiscardBackingStoreMsg(BackingStoreMsgProxy* proxy);

  // Called on the UI thread to dispatch a paint message if necessary.
  void OnDispatchBackingStoreMsg(BackingStoreMsgProxy* proxy);

  // Called on the UI thread to finish creating a window.
  void OnCreateWindowOnUI(
      const ViewHostMsg_CreateWindow_Params& params,
      int route_id,
      int main_frame_route_id,
      SessionStorageNamespace* session_storage_namespace);

  // Called on the IO thread after a window was created on the UI thread.
  void OnResumeRequestsForView(int route_id);

  // Called on the UI thread to finish creating a widget.
  void OnCreateWidgetOnUI(int opener_id,
                          int route_id,
                          WebKit::WebPopupType popup_type);

  // Called on the UI thread to create a fullscreen widget.
  void OnCreateFullscreenWidgetOnUI(int opener_id, int route_id);

  // Called on the IO thread to resume a paused navigation in the network
  // stack without transferring it to a new renderer process.
  void OnResumeDeferredNavigation(const GlobalRequestID& request_id);

#if defined(OS_POSIX)
  // Called on destruction to release all allocated transport DIBs
  void ClearAllocatedDIBs();

  // On POSIX we keep file descriptors to all the allocated DIBs around until
  // the renderer frees them.
  base::Lock allocated_dibs_lock_;
  std::map<TransportDIB::Id, int> allocated_dibs_;
#endif

  // A map of live paint messages.  Must hold pending_paints_lock_ to access.
  // The BackingStoreMsgProxy objects are not owned by this map. (See
  // BackingStoreMsgProxy for details about how the lifetime of instances are
  // managed.)
  BackingStoreMsgProxyMap pending_paints_;
  base::Lock pending_paints_lock_;

  int render_process_id_;

  // Event used to implement WaitForBackingStoreMsg.
  base::WaitableEvent event_;

  // The next routing id to use.
  base::AtomicSequenceNumber next_routing_id_;

  ResourceDispatcherHostImpl* resource_dispatcher_host_;

  DISALLOW_COPY_AND_ASSIGN(RenderWidgetHelper);
};

}  // namespace content

#endif  // CONTENT_BROWSER_RENDERER_HOST_RENDER_WIDGET_HELPER_H_