Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / ppapi / proxy / message_handler.cc
1 // Copyright 2014 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 "ppapi/proxy/message_handler.h"
6
7 #include "ipc/ipc_message.h"
8 #include "ppapi/proxy/plugin_dispatcher.h"
9 #include "ppapi/proxy/ppapi_messages.h"
10 #include "ppapi/proxy/ppb_message_loop_proxy.h"
11 #include "ppapi/shared_impl/proxy_lock.h"
12 #include "ppapi/shared_impl/scoped_pp_var.h"
13 #include "ppapi/thunk/enter.h"
14
15 namespace ppapi {
16 namespace proxy {
17 namespace {
18
19 typedef void (*HandleMessageFunc)(PP_Instance, void*, const PP_Var*);
20 typedef void (*HandleBlockingMessageFunc)(
21     PP_Instance, void*, const PP_Var*, PP_Var*);
22 typedef void (*HandleMessageFunc_0_1)(PP_Instance, void*, PP_Var);
23 typedef PP_Var (*HandleBlockingMessageFunc_0_1)(PP_Instance, void*, PP_Var);
24
25 void HandleMessageWrapper(HandleMessageFunc function,
26                           PP_Instance instance,
27                           void* user_data,
28                           ScopedPPVar message_data) {
29   CallWhileUnlocked(function, instance, user_data,
30                     &message_data.get());
31 }
32
33 void HandleBlockingMessageWrapper(HandleBlockingMessageFunc function,
34                                   PP_Instance instance,
35                                   void* user_data,
36                                   ScopedPPVar message_data,
37                                   scoped_ptr<IPC::Message> reply_msg) {
38   PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
39   if (!dispatcher)
40     return;
41   PP_Var result = PP_MakeUndefined();
42   MessageLoopResource::GetCurrent()->
43       set_currently_handling_blocking_message(true);
44   CallWhileUnlocked(
45       function, instance, user_data, &message_data.get(), &result);
46   MessageLoopResource::GetCurrent()->
47       set_currently_handling_blocking_message(false);
48   PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams(
49       reply_msg.get(),
50       SerializedVarReturnValue::Convert(dispatcher, result),
51       true /* was_handled */);
52   dispatcher->Send(reply_msg.release());
53 }
54
55 // TODO(dmichael): Remove the 0_1 verions; crbug.com/414398
56 void HandleMessageWrapper_0_1(HandleMessageFunc_0_1 function,
57                               PP_Instance instance,
58                               void* user_data,
59                               ScopedPPVar message_data) {
60   CallWhileUnlocked(function, instance, user_data, message_data.get());
61 }
62
63 void HandleBlockingMessageWrapper_0_1(HandleBlockingMessageFunc_0_1 function,
64                                       PP_Instance instance,
65                                       void* user_data,
66                                       ScopedPPVar message_data,
67                                       scoped_ptr<IPC::Message> reply_msg) {
68   PluginDispatcher* dispatcher = PluginDispatcher::GetForInstance(instance);
69   if (!dispatcher)
70     return;
71   MessageLoopResource::GetCurrent()->
72       set_currently_handling_blocking_message(true);
73   PP_Var return_value = CallWhileUnlocked(function,
74                                           instance,
75                                           user_data,
76                                           message_data.get());
77   MessageLoopResource::GetCurrent()->
78       set_currently_handling_blocking_message(false);
79   PpapiMsg_PPPMessageHandler_HandleBlockingMessage::WriteReplyParams(
80       reply_msg.get(),
81       SerializedVarReturnValue::Convert(dispatcher, return_value),
82       true /* was_handled */);
83   dispatcher->Send(reply_msg.release());
84 }
85
86 }  // namespace
87
88 // static
89 scoped_ptr<MessageHandler> MessageHandler::Create(
90       PP_Instance instance,
91       const PPP_MessageHandler_0_2* handler_if,
92       void* user_data,
93       PP_Resource message_loop,
94       int32_t* error) {
95   scoped_ptr<MessageHandler> result;
96   // The interface and all function pointers must be valid.
97   if (!handler_if ||
98       !handler_if->HandleMessage ||
99       !handler_if->HandleBlockingMessage ||
100       !handler_if->Destroy) {
101     *error = PP_ERROR_BADARGUMENT;
102     return result.Pass();
103   }
104   thunk::EnterResourceNoLock<thunk::PPB_MessageLoop_API>
105       enter_loop(message_loop, true);
106   if (enter_loop.failed()) {
107     *error = PP_ERROR_BADRESOURCE;
108     return result.Pass();
109   }
110   scoped_refptr<MessageLoopResource> message_loop_resource(
111       static_cast<MessageLoopResource*>(enter_loop.object()));
112   if (message_loop_resource->is_main_thread_loop()) {
113     *error = PP_ERROR_WRONG_THREAD;
114     return result.Pass();
115   }
116
117   result.reset(new MessageHandler(
118       instance, handler_if, user_data, message_loop_resource));
119   *error = PP_OK;
120   return result.Pass();
121 }
122
123 // CreateDeprecated is a near-exact copy of Create, but we'll just delete it
124 // when 0.1 is deprecated, so need to get fancy to avoid code duplication.
125 // TODO(dmichael) crbug.com/414398
126 // static
127 scoped_ptr<MessageHandler> MessageHandler::CreateDeprecated(
128       PP_Instance instance,
129       const PPP_MessageHandler_0_1_Deprecated* handler_if,
130       void* user_data,
131       PP_Resource message_loop,
132       int32_t* error) {
133   scoped_ptr<MessageHandler> result;
134   // The interface and all function pointers must be valid.
135   if (!handler_if ||
136       !handler_if->HandleMessage ||
137       !handler_if->HandleBlockingMessage ||
138       !handler_if->Destroy) {
139     *error = PP_ERROR_BADARGUMENT;
140     return result.Pass();
141   }
142   thunk::EnterResourceNoLock<thunk::PPB_MessageLoop_API>
143       enter_loop(message_loop, true);
144   if (enter_loop.failed()) {
145     *error = PP_ERROR_BADRESOURCE;
146     return result.Pass();
147   }
148   scoped_refptr<MessageLoopResource> message_loop_resource(
149       static_cast<MessageLoopResource*>(enter_loop.object()));
150   if (message_loop_resource->is_main_thread_loop()) {
151     *error = PP_ERROR_WRONG_THREAD;
152     return result.Pass();
153   }
154
155   result.reset(new MessageHandler(
156       instance, handler_if, user_data, message_loop_resource));
157   *error = PP_OK;
158   return result.Pass();
159 }
160
161 MessageHandler::~MessageHandler() {
162   // It's possible the message_loop_proxy is NULL if that loop has been quit.
163   // In that case, we unfortunately just can't call Destroy.
164   if (message_loop_->message_loop_proxy().get()) {
165     // The posted task won't have the proxy lock, but that's OK, it doesn't
166     // touch any internal state; it's a direct call on the plugin's function.
167     if (handler_if_0_1_) {
168       message_loop_->message_loop_proxy()->PostTask(FROM_HERE,
169           base::Bind(handler_if_0_1_->Destroy,
170                      instance_,
171                      user_data_));
172       return;
173     }
174     message_loop_->message_loop_proxy()->PostTask(FROM_HERE,
175         base::Bind(handler_if_->Destroy,
176                    instance_,
177                    user_data_));
178   }
179 }
180
181 bool MessageHandler::LoopIsValid() const {
182   return !!message_loop_->message_loop_proxy().get();
183 }
184
185 void MessageHandler::HandleMessage(ScopedPPVar var) {
186   if (handler_if_0_1_) {
187     // TODO(dmichael): Remove this code path. crbug.com/414398
188     message_loop_->message_loop_proxy()->PostTask(FROM_HERE,
189         RunWhileLocked(base::Bind(&HandleMessageWrapper_0_1,
190                                   handler_if_0_1_->HandleMessage,
191                                   instance_,
192                                   user_data_,
193                                   var)));
194     return;
195   }
196   message_loop_->message_loop_proxy()->PostTask(FROM_HERE,
197       RunWhileLocked(base::Bind(&HandleMessageWrapper,
198                                 handler_if_->HandleMessage,
199                                 instance_,
200                                 user_data_,
201                                 var)));
202 }
203
204 void MessageHandler::HandleBlockingMessage(ScopedPPVar var,
205                                            scoped_ptr<IPC::Message> reply_msg) {
206   if (handler_if_0_1_) {
207     // TODO(dmichael): Remove this code path. crbug.com/414398
208     message_loop_->message_loop_proxy()->PostTask(FROM_HERE,
209         RunWhileLocked(base::Bind(&HandleBlockingMessageWrapper_0_1,
210                                   handler_if_0_1_->HandleBlockingMessage,
211                                   instance_,
212                                   user_data_,
213                                   var,
214                                   base::Passed(reply_msg.Pass()))));
215     return;
216   }
217   message_loop_->message_loop_proxy()->PostTask(FROM_HERE,
218       RunWhileLocked(base::Bind(&HandleBlockingMessageWrapper,
219                                 handler_if_->HandleBlockingMessage,
220                                 instance_,
221                                 user_data_,
222                                 var,
223                                 base::Passed(reply_msg.Pass()))));
224 }
225
226 MessageHandler::MessageHandler(
227     PP_Instance instance,
228     const PPP_MessageHandler_0_2* handler_if,
229     void* user_data,
230     scoped_refptr<MessageLoopResource> message_loop)
231     : instance_(instance),
232       handler_if_(handler_if),
233       handler_if_0_1_(NULL),
234       user_data_(user_data),
235       message_loop_(message_loop) {
236 }
237
238 MessageHandler::MessageHandler(
239     PP_Instance instance,
240     const PPP_MessageHandler_0_1_Deprecated* handler_if,
241     void* user_data,
242     scoped_refptr<MessageLoopResource> message_loop)
243     : instance_(instance),
244       handler_if_(NULL),
245       handler_if_0_1_(handler_if),
246       user_data_(user_data),
247       message_loop_(message_loop) {
248 }
249
250 }  // namespace proxy
251 }  // namespace ppapi