blob: 0c21e377733751873561ff42642fd1df3a818fba [file] [log] [blame]
[email protected]aaa11b32012-03-08 12:30:131// Copyright (c) 2012 The Chromium Authors. All rights reserved.
[email protected]eeb4e4a2011-07-19 16:22:062// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "ppapi/proxy/ppb_graphics_3d_proxy.h"
6
brettw669d47b12015-02-13 21:17:387#include "base/numerics/safe_conversions.h"
avie029c4132015-12-23 06:45:228#include "build/build_config.h"
[email protected]eeb4e4a2011-07-19 16:22:069#include "gpu/command_buffer/client/gles2_implementation.h"
[email protected]84b44c552012-10-15 20:58:1710#include "gpu/command_buffer/common/command_buffer.h"
dyenddfdbbb2016-01-14 22:21:3811#include "gpu/command_buffer/common/sync_token.h"
[email protected]eeb4e4a2011-07-19 16:22:0612#include "ppapi/c/pp_errors.h"
13#include "ppapi/proxy/enter_proxy.h"
14#include "ppapi/proxy/plugin_dispatcher.h"
[email protected]aaa11b32012-03-08 12:30:1315#include "ppapi/proxy/ppapi_command_buffer_proxy.h"
[email protected]eeb4e4a2011-07-19 16:22:0616#include "ppapi/proxy/ppapi_messages.h"
[email protected]84b44c552012-10-15 20:58:1717#include "ppapi/shared_impl/ppapi_globals.h"
[email protected]eeb4e4a2011-07-19 16:22:0618#include "ppapi/thunk/enter.h"
19#include "ppapi/thunk/resource_creation_api.h"
20#include "ppapi/thunk/thunk.h"
21
[email protected]eeb4e4a2011-07-19 16:22:0622using ppapi::thunk::EnterResourceNoLock;
23using ppapi::thunk::PPB_Graphics3D_API;
24using ppapi::thunk::ResourceCreationAPI;
25
[email protected]4d2efd22011-08-18 21:58:0226namespace ppapi {
[email protected]eeb4e4a2011-07-19 16:22:0627namespace proxy {
28
29namespace {
[email protected]84b44c552012-10-15 20:58:1730
avie029c4132015-12-23 06:45:2231const int32_t kCommandBufferSize = 1024 * 1024;
32const int32_t kTransferBufferSize = 1024 * 1024;
[email protected]eeb4e4a2011-07-19 16:22:0633
mazda9cfbcfb2014-11-12 17:07:1134#if !defined(OS_NACL)
penghuanga206fb492014-09-09 21:27:3235base::SharedMemoryHandle TransportSHMHandle(
36 Dispatcher* dispatcher,
37 const base::SharedMemoryHandle& handle) {
[email protected]eeb4e4a2011-07-19 16:22:0638 // Don't close the handle, it doesn't belong to us.
erikchen4fc32d52015-06-02 02:16:3839 return dispatcher->ShareSharedMemoryHandleWithRemote(handle);
[email protected]eeb4e4a2011-07-19 16:22:0640}
mazda9cfbcfb2014-11-12 17:07:1141#endif // !defined(OS_NACL)
[email protected]eeb4e4a2011-07-19 16:22:0642
[email protected]914f5262013-06-01 00:17:2243gpu::CommandBuffer::State GetErrorState() {
44 gpu::CommandBuffer::State error_state;
45 error_state.error = gpu::error::kGenericError;
[email protected]eeb4e4a2011-07-19 16:22:0646 return error_state;
47}
48
[email protected]eeb4e4a2011-07-19 16:22:0649} // namespace
50
51Graphics3D::Graphics3D(const HostResource& resource)
[email protected]4e46a732013-09-30 18:35:5952 : PPB_Graphics3D_Shared(resource) {
[email protected]eeb4e4a2011-07-19 16:22:0653}
54
55Graphics3D::~Graphics3D() {
[email protected]edccb562013-10-02 00:01:2056 DestroyGLES2Impl();
[email protected]eeb4e4a2011-07-19 16:22:0657}
58
penghuanga206fb492014-09-09 21:27:3259bool Graphics3D::Init(gpu::gles2::GLES2Implementation* share_gles2,
piman360175c2014-11-07 02:30:0160 const gpu::Capabilities& capabilities,
dyen12e45962015-09-18 00:13:5161 const SerializedHandle& shared_state,
lukasza2573ce7d2016-02-16 19:17:2262 gpu::CommandBufferId command_buffer_id) {
[email protected]7f8b26b2011-08-18 15:41:0163 PluginDispatcher* dispatcher = PluginDispatcher::GetForResource(this);
[email protected]eeb4e4a2011-07-19 16:22:0664 if (!dispatcher)
65 return false;
66
piman360175c2014-11-07 02:30:0167 command_buffer_.reset(new PpapiCommandBufferProxy(
dyen12e45962015-09-18 00:13:5168 host_resource(), dispatcher, capabilities, shared_state,
69 command_buffer_id));
[email protected]84b44c552012-10-15 20:58:1770
[email protected]9ed07f82012-05-29 21:54:5571 return CreateGLES2Impl(kCommandBufferSize, kTransferBufferSize,
72 share_gles2);
[email protected]eeb4e4a2011-07-19 16:22:0673}
74
[email protected]503b3a22011-12-12 23:29:4075PP_Bool Graphics3D::SetGetBuffer(int32_t /* transfer_buffer_id */) {
[email protected]eeb4e4a2011-07-19 16:22:0676 return PP_FALSE;
77}
78
[email protected]eeb4e4a2011-07-19 16:22:0679PP_Bool Graphics3D::Flush(int32_t put_offset) {
80 return PP_FALSE;
81}
82
[email protected]046fa1ac2014-04-01 09:06:4383scoped_refptr<gpu::Buffer> Graphics3D::CreateTransferBuffer(
84 uint32_t size,
85 int32_t* id) {
86 *id = -1;
87 return NULL;
[email protected]eeb4e4a2011-07-19 16:22:0688}
89
90PP_Bool Graphics3D::DestroyTransferBuffer(int32_t id) {
91 return PP_FALSE;
92}
93
[email protected]7fe4198b2014-03-18 21:52:3694gpu::CommandBuffer::State Graphics3D::WaitForTokenInRange(int32_t start,
95 int32_t end) {
96 return GetErrorState();
97}
98
99gpu::CommandBuffer::State Graphics3D::WaitForGetOffsetInRange(int32_t start,
100 int32_t end) {
[email protected]eeb4e4a2011-07-19 16:22:06101 return GetErrorState();
102}
103
dyen4de3d345f2016-01-12 18:30:42104void Graphics3D::EnsureWorkVisible() {
105 NOTREACHED();
106}
107
erikchen438b0442016-05-11 18:33:30108void Graphics3D::TakeFrontBuffer() {
109 NOTREACHED();
110}
111
[email protected]eeb4e4a2011-07-19 16:22:06112gpu::CommandBuffer* Graphics3D::GetCommandBuffer() {
[email protected]4e46a732013-09-30 18:35:59113 return command_buffer_.get();
[email protected]eeb4e4a2011-07-19 16:22:06114}
115
[email protected]744e0792013-09-27 01:18:35116gpu::GpuControl* Graphics3D::GetGpuControl() {
117 return command_buffer_.get();
118}
119
dyenddfdbbb2016-01-14 22:21:38120int32_t Graphics3D::DoSwapBuffers(const gpu::SyncToken& sync_token) {
121 // A valid sync token would indicate a swap buffer already happened somehow.
122 DCHECK(!sync_token.HasData());
123
124 gpu::gles2::GLES2Implementation* gl = gles2_impl();
125 gl->SwapBuffers();
erikchen438b0442016-05-11 18:33:30126
127 PluginDispatcher::GetForResource(this)->Send(
128 new PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer(API_ID_PPB_GRAPHICS_3D,
129 host_resource()));
130
dyenddfdbbb2016-01-14 22:21:38131 const GLuint64 fence_sync = gl->InsertFenceSyncCHROMIUM();
132 gl->ShallowFlushCHROMIUM();
133
134 gpu::SyncToken new_sync_token;
135 gl->GenSyncTokenCHROMIUM(fence_sync, new_sync_token.GetData());
136
[email protected]eeb4e4a2011-07-19 16:22:06137 IPC::Message* msg = new PpapiHostMsg_PPBGraphics3D_SwapBuffers(
dyenddfdbbb2016-01-14 22:21:38138 API_ID_PPB_GRAPHICS_3D, host_resource(), new_sync_token);
[email protected]eeb4e4a2011-07-19 16:22:06139 msg->set_unblock(true);
[email protected]7f8b26b2011-08-18 15:41:01140 PluginDispatcher::GetForResource(this)->Send(msg);
[email protected]eeb4e4a2011-07-19 16:22:06141
[email protected]eeb4e4a2011-07-19 16:22:06142 return PP_OK_COMPLETIONPENDING;
143}
144
[email protected]5c966022011-09-13 18:09:37145PPB_Graphics3D_Proxy::PPB_Graphics3D_Proxy(Dispatcher* dispatcher)
146 : InterfaceProxy(dispatcher),
[email protected]a2f53dc2013-04-30 01:06:35147 callback_factory_(this) {
[email protected]eeb4e4a2011-07-19 16:22:06148}
149
150PPB_Graphics3D_Proxy::~PPB_Graphics3D_Proxy() {
151}
152
153// static
[email protected]eeb4e4a2011-07-19 16:22:06154PP_Resource PPB_Graphics3D_Proxy::CreateProxyResource(
155 PP_Instance instance,
[email protected]eeb4e4a2011-07-19 16:22:06156 PP_Resource share_context,
157 const int32_t* attrib_list) {
158 PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
159 if (!dispatcher)
160 return PP_ERROR_BADARGUMENT;
161
[email protected]9ed07f82012-05-29 21:54:55162 HostResource share_host;
163 gpu::gles2::GLES2Implementation* share_gles2 = NULL;
164 if (share_context != 0) {
165 EnterResourceNoLock<PPB_Graphics3D_API> enter(share_context, true);
166 if (enter.failed())
167 return PP_ERROR_BADARGUMENT;
168
169 PPB_Graphics3D_Shared* share_graphics =
170 static_cast<PPB_Graphics3D_Shared*>(enter.object());
171 share_host = share_graphics->host_resource();
172 share_gles2 = share_graphics->gles2_impl();
173 }
[email protected]eeb4e4a2011-07-19 16:22:06174
175 std::vector<int32_t> attribs;
176 if (attrib_list) {
177 for (const int32_t* attr = attrib_list;
[email protected]0e50fc4d2011-08-01 15:33:51178 attr[0] != PP_GRAPHICS3DATTRIB_NONE;
179 attr += 2) {
180 attribs.push_back(attr[0]);
181 attribs.push_back(attr[1]);
[email protected]eeb4e4a2011-07-19 16:22:06182 }
[email protected]eeb4e4a2011-07-19 16:22:06183 }
[email protected]0e50fc4d2011-08-01 15:33:51184 attribs.push_back(PP_GRAPHICS3DATTRIB_NONE);
[email protected]eeb4e4a2011-07-19 16:22:06185
186 HostResource result;
piman360175c2014-11-07 02:30:01187 gpu::Capabilities capabilities;
penghuanga206fb492014-09-09 21:27:32188 ppapi::proxy::SerializedHandle shared_state;
lukasza2573ce7d2016-02-16 19:17:22189 gpu::CommandBufferId command_buffer_id;
penghuanga206fb492014-09-09 21:27:32190 dispatcher->Send(new PpapiHostMsg_PPBGraphics3D_Create(API_ID_PPB_GRAPHICS_3D,
dyen12e45962015-09-18 00:13:51191 instance, share_host, attribs, &result, &capabilities, &shared_state,
192 &command_buffer_id));
penghuanga206fb492014-09-09 21:27:32193
[email protected]eeb4e4a2011-07-19 16:22:06194 if (result.is_null())
195 return 0;
196
[email protected]51e1aec2011-08-11 04:48:30197 scoped_refptr<Graphics3D> graphics_3d(new Graphics3D(result));
dyen12e45962015-09-18 00:13:51198 if (!graphics_3d->Init(share_gles2, capabilities, shared_state,
199 command_buffer_id)) {
[email protected]eeb4e4a2011-07-19 16:22:06200 return 0;
dyen12e45962015-09-18 00:13:51201 }
[email protected]7f8b26b2011-08-18 15:41:01202 return graphics_3d->GetReference();
[email protected]eeb4e4a2011-07-19 16:22:06203}
204
205bool PPB_Graphics3D_Proxy::OnMessageReceived(const IPC::Message& msg) {
206 bool handled = true;
207 IPC_BEGIN_MESSAGE_MAP(PPB_Graphics3D_Proxy, msg)
[email protected]11494c5c2012-11-13 02:50:57208#if !defined(OS_NACL)
[email protected]eeb4e4a2011-07-19 16:22:06209 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_Create,
210 OnMsgCreate)
[email protected]503b3a22011-12-12 23:29:40211 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SetGetBuffer,
212 OnMsgSetGetBuffer)
[email protected]7fe4198b2014-03-18 21:52:36213 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_WaitForTokenInRange,
214 OnMsgWaitForTokenInRange)
215 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_WaitForGetOffsetInRange,
216 OnMsgWaitForGetOffsetInRange)
217 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_AsyncFlush, OnMsgAsyncFlush)
[email protected]eeb4e4a2011-07-19 16:22:06218 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_CreateTransferBuffer,
219 OnMsgCreateTransferBuffer)
220 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_DestroyTransferBuffer,
221 OnMsgDestroyTransferBuffer)
[email protected]eeb4e4a2011-07-19 16:22:06222 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_SwapBuffers,
223 OnMsgSwapBuffers)
erikchen438b0442016-05-11 18:33:30224 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_TakeFrontBuffer,
225 OnMsgTakeFrontBuffer)
dyen4de3d345f2016-01-12 18:30:42226 IPC_MESSAGE_HANDLER(PpapiHostMsg_PPBGraphics3D_EnsureWorkVisible,
227 OnMsgEnsureWorkVisible)
[email protected]11494c5c2012-11-13 02:50:57228#endif // !defined(OS_NACL)
[email protected]eeb4e4a2011-07-19 16:22:06229
230 IPC_MESSAGE_HANDLER(PpapiMsg_PPBGraphics3D_SwapBuffersACK,
231 OnMsgSwapBuffersACK)
232 IPC_MESSAGE_UNHANDLED(handled = false)
233
234 IPC_END_MESSAGE_MAP()
235 // FIXME(brettw) handle bad messages!
236 return handled;
237}
238
[email protected]11494c5c2012-11-13 02:50:57239#if !defined(OS_NACL)
lukasza2573ce7d2016-02-16 19:17:22240void PPB_Graphics3D_Proxy::OnMsgCreate(
241 PP_Instance instance,
242 HostResource share_context,
243 const std::vector<int32_t>& attribs,
244 HostResource* result,
245 gpu::Capabilities* capabilities,
246 SerializedHandle* shared_state,
247 gpu::CommandBufferId* command_buffer_id) {
penghuanga206fb492014-09-09 21:27:32248 shared_state->set_null_shmem();
[email protected]48c1db72012-12-17 20:56:11249 if (attribs.empty() ||
250 attribs.back() != PP_GRAPHICS3DATTRIB_NONE ||
251 !(attribs.size() & 1))
[email protected]eeb4e4a2011-07-19 16:22:06252 return; // Bad message.
253
[email protected]5c966022011-09-13 18:09:37254 thunk::EnterResourceCreation enter(instance);
[email protected]9ed07f82012-05-29 21:54:55255
penghuanga206fb492014-09-09 21:27:32256 if (!enter.succeeded())
257 return;
258
erikchen4fc32d52015-06-02 02:16:38259 base::SharedMemoryHandle handle = base::SharedMemory::NULLHandle();
penghuanga206fb492014-09-09 21:27:32260 result->SetHostResource(
[email protected]9ed07f82012-05-29 21:54:55261 instance,
262 enter.functions()->CreateGraphics3DRaw(instance,
263 share_context.host_resource(),
penghuanga206fb492014-09-09 21:27:32264 &attribs.front(),
piman360175c2014-11-07 02:30:01265 capabilities,
dyen12e45962015-09-18 00:13:51266 &handle,
267 command_buffer_id));
penghuanga206fb492014-09-09 21:27:32268 if (!result->is_null()) {
269 shared_state->set_shmem(TransportSHMHandle(dispatcher(), handle),
270 sizeof(gpu::CommandBuffer::State));
[email protected]eeb4e4a2011-07-19 16:22:06271 }
272}
273
avie029c4132015-12-23 06:45:22274void PPB_Graphics3D_Proxy::OnMsgSetGetBuffer(const HostResource& context,
275 int32_t transfer_buffer_id) {
[email protected]503b3a22011-12-12 23:29:40276 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
277 if (enter.succeeded())
278 enter.object()->SetGetBuffer(transfer_buffer_id);
[email protected]eeb4e4a2011-07-19 16:22:06279}
280
[email protected]7fe4198b2014-03-18 21:52:36281void PPB_Graphics3D_Proxy::OnMsgWaitForTokenInRange(
282 const HostResource& context,
avie029c4132015-12-23 06:45:22283 int32_t start,
284 int32_t end,
[email protected]7fe4198b2014-03-18 21:52:36285 gpu::CommandBuffer::State* state,
286 bool* success) {
[email protected]eeb4e4a2011-07-19 16:22:06287 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
[email protected]571b35e82012-05-19 00:04:35288 if (enter.failed()) {
289 *success = false;
[email protected]eeb4e4a2011-07-19 16:22:06290 return;
[email protected]571b35e82012-05-19 00:04:35291 }
[email protected]7fe4198b2014-03-18 21:52:36292 *state = enter.object()->WaitForTokenInRange(start, end);
293 *success = true;
294}
295
296void PPB_Graphics3D_Proxy::OnMsgWaitForGetOffsetInRange(
297 const HostResource& context,
avie029c4132015-12-23 06:45:22298 int32_t start,
299 int32_t end,
[email protected]7fe4198b2014-03-18 21:52:36300 gpu::CommandBuffer::State* state,
301 bool* success) {
302 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
303 if (enter.failed()) {
304 *success = false;
305 return;
306 }
307 *state = enter.object()->WaitForGetOffsetInRange(start, end);
[email protected]571b35e82012-05-19 00:04:35308 *success = true;
[email protected]eeb4e4a2011-07-19 16:22:06309}
310
311void PPB_Graphics3D_Proxy::OnMsgAsyncFlush(const HostResource& context,
avie029c4132015-12-23 06:45:22312 int32_t put_offset) {
[email protected]eeb4e4a2011-07-19 16:22:06313 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
314 if (enter.succeeded())
315 enter.object()->Flush(put_offset);
316}
317
318void PPB_Graphics3D_Proxy::OnMsgCreateTransferBuffer(
319 const HostResource& context,
avie029c4132015-12-23 06:45:22320 uint32_t size,
321 int32_t* id,
penghuanga206fb492014-09-09 21:27:32322 SerializedHandle* transfer_buffer) {
[email protected]046fa1ac2014-04-01 09:06:43323 transfer_buffer->set_null_shmem();
[email protected]eeb4e4a2011-07-19 16:22:06324 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
[email protected]046fa1ac2014-04-01 09:06:43325 if (enter.succeeded()) {
326 scoped_refptr<gpu::Buffer> buffer =
327 enter.object()->CreateTransferBuffer(size, id);
Daniel Cheng6d3ae972014-08-26 00:27:38328 if (!buffer.get())
[email protected]046fa1ac2014-04-01 09:06:43329 return;
[email protected]8a978df2014-04-02 23:54:09330 gpu::SharedMemoryBufferBacking* backing =
331 static_cast<gpu::SharedMemoryBufferBacking*>(buffer->backing());
332 DCHECK(backing && backing->shared_memory());
[email protected]046fa1ac2014-04-01 09:06:43333 transfer_buffer->set_shmem(
penghuanga206fb492014-09-09 21:27:32334 TransportSHMHandle(dispatcher(), backing->shared_memory()->handle()),
brettw669d47b12015-02-13 21:17:38335 base::checked_cast<uint32_t>(buffer->size()));
[email protected]046fa1ac2014-04-01 09:06:43336 } else {
[email protected]67c80782012-12-21 01:16:52337 *id = -1;
[email protected]046fa1ac2014-04-01 09:06:43338 }
[email protected]eeb4e4a2011-07-19 16:22:06339}
340
341void PPB_Graphics3D_Proxy::OnMsgDestroyTransferBuffer(
342 const HostResource& context,
avie029c4132015-12-23 06:45:22343 int32_t id) {
[email protected]eeb4e4a2011-07-19 16:22:06344 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
345 if (enter.succeeded())
346 enter.object()->DestroyTransferBuffer(id);
347}
348
dyenddfdbbb2016-01-14 22:21:38349void PPB_Graphics3D_Proxy::OnMsgSwapBuffers(const HostResource& context,
350 const gpu::SyncToken& sync_token) {
[email protected]79d23c72011-08-08 19:40:40351 EnterHostFromHostResourceForceCallback<PPB_Graphics3D_API> enter(
352 context, callback_factory_,
[email protected]eeb4e4a2011-07-19 16:22:06353 &PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin, context);
[email protected]eeb4e4a2011-07-19 16:22:06354 if (enter.succeeded())
raymesbc71ad0b2016-03-14 07:30:35355 enter.SetResult(
356 enter.object()->SwapBuffersWithSyncToken(enter.callback(), sync_token));
[email protected]eeb4e4a2011-07-19 16:22:06357}
[email protected]b096d032013-03-08 03:08:01358
erikchen438b0442016-05-11 18:33:30359void PPB_Graphics3D_Proxy::OnMsgTakeFrontBuffer(const HostResource& context) {
360 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
361 if (enter.succeeded())
362 enter.object()->TakeFrontBuffer();
363}
364
dyen4de3d345f2016-01-12 18:30:42365void PPB_Graphics3D_Proxy::OnMsgEnsureWorkVisible(const HostResource& context) {
366 EnterHostFromHostResource<PPB_Graphics3D_API> enter(context);
367 if (enter.succeeded())
368 enter.object()->EnsureWorkVisible();
369}
[email protected]11494c5c2012-11-13 02:50:57370#endif // !defined(OS_NACL)
[email protected]eeb4e4a2011-07-19 16:22:06371
372void PPB_Graphics3D_Proxy::OnMsgSwapBuffersACK(const HostResource& resource,
373 int32_t pp_error) {
374 EnterPluginFromHostResource<PPB_Graphics3D_API> enter(resource);
375 if (enter.succeeded())
376 static_cast<Graphics3D*>(enter.object())->SwapBuffersACK(pp_error);
377}
378
[email protected]11494c5c2012-11-13 02:50:57379#if !defined(OS_NACL)
[email protected]eeb4e4a2011-07-19 16:22:06380void PPB_Graphics3D_Proxy::SendSwapBuffersACKToPlugin(
381 int32_t result,
382 const HostResource& context) {
383 dispatcher()->Send(new PpapiMsg_PPBGraphics3D_SwapBuffersACK(
[email protected]ac4b54d2011-10-20 23:09:28384 API_ID_PPB_GRAPHICS_3D, context, result));
[email protected]eeb4e4a2011-07-19 16:22:06385}
[email protected]11494c5c2012-11-13 02:50:57386#endif // !defined(OS_NACL)
[email protected]eeb4e4a2011-07-19 16:22:06387
388} // namespace proxy
[email protected]4d2efd22011-08-18 21:58:02389} // namespace ppapi