1// Copyright (c) 2013 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 "chrome/renderer/pepper/pepper_extensions_common_host.h"
6
7#include "base/logging.h"
8#include "base/memory/scoped_ptr.h"
9#include "base/values.h"
10#include "chrome/renderer/extensions/chrome_v8_context.h"
11#include "chrome/renderer/extensions/dispatcher.h"
12#include "chrome/renderer/extensions/extension_helper.h"
13#include "content/public/renderer/render_view.h"
14#include "content/public/renderer/renderer_ppapi_host.h"
15#include "ppapi/c/pp_errors.h"
16#include "ppapi/host/dispatch_host_message.h"
17#include "ppapi/host/host_message_context.h"
18#include "ppapi/host/ppapi_host.h"
19#include "ppapi/proxy/ppapi_messages.h"
20#include "third_party/WebKit/public/web/WebDocument.h"
21#include "third_party/WebKit/public/web/WebElement.h"
22#include "third_party/WebKit/public/web/WebFrame.h"
23#include "third_party/WebKit/public/web/WebPluginContainer.h"
24
25namespace chrome {
26
27PepperExtensionsCommonHost::PepperExtensionsCommonHost(
28    content::RendererPpapiHost* host,
29    PP_Instance instance,
30    PP_Resource resource,
31    extensions::Dispatcher* dispatcher)
32    : ResourceHost(host->GetPpapiHost(), instance, resource),
33      renderer_ppapi_host_(host),
34      dispatcher_(dispatcher) {
35}
36
37PepperExtensionsCommonHost::~PepperExtensionsCommonHost() {
38  dispatcher_->request_sender()->InvalidateSource(this);
39}
40
41// static
42PepperExtensionsCommonHost* PepperExtensionsCommonHost::Create(
43    content::RendererPpapiHost* host,
44    PP_Instance instance,
45    PP_Resource resource) {
46  content::RenderView* render_view = host->GetRenderViewForInstance(instance);
47  if (!render_view)
48    return NULL;
49  extensions::ExtensionHelper* extension_helper =
50      extensions::ExtensionHelper::Get(render_view);
51  if (!extension_helper)
52    return NULL;
53  extensions::Dispatcher* dispatcher = extension_helper->dispatcher();
54  if (!dispatcher)
55    return NULL;
56
57  return new PepperExtensionsCommonHost(host, instance, resource, dispatcher);
58}
59
60int32_t PepperExtensionsCommonHost::OnResourceMessageReceived(
61    const IPC::Message& msg,
62    ppapi::host::HostMessageContext* context) {
63  IPC_BEGIN_MESSAGE_MAP(PepperExtensionsCommonHost, msg)
64    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_ExtensionsCommon_Post,
65                                      OnPost)
66    PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_ExtensionsCommon_Call,
67                                      OnCall)
68  IPC_END_MESSAGE_MAP()
69  return PP_ERROR_FAILED;
70}
71
72extensions::ChromeV8Context* PepperExtensionsCommonHost::GetContext() {
73  WebKit::WebPluginContainer* container =
74      renderer_ppapi_host_->GetContainerForInstance(pp_instance());
75  if (!container)
76    return NULL;
77
78  WebKit::WebFrame* frame = container->element().document().frame();
79  v8::HandleScope scope;
80  return dispatcher_->v8_context_set().GetByV8Context(
81      frame->mainWorldScriptContext());
82}
83
84void PepperExtensionsCommonHost::OnResponseReceived(
85    const std::string& /* name */,
86    int request_id,
87    bool success,
88    const base::ListValue& response,
89    const std::string& /* error */) {
90  PendingRequestMap::iterator iter = pending_request_map_.find(request_id);
91
92  // Ignore responses resulted from calls to OnPost().
93  if (iter == pending_request_map_.end()) {
94    DCHECK_EQ(0u, response.GetSize());
95    return;
96  }
97
98  linked_ptr<ppapi::host::ReplyMessageContext> context = iter->second;
99  pending_request_map_.erase(iter);
100
101  context->params.set_result(success ? PP_OK : PP_ERROR_FAILED);
102  SendReply(*context, PpapiPluginMsg_ExtensionsCommon_CallReply(response));
103}
104
105int32_t PepperExtensionsCommonHost::OnPost(
106    ppapi::host::HostMessageContext* context,
107    const std::string& request_name,
108    base::ListValue& args) {
109  // TODO(yzshen): Add support for calling into JS for APIs that have custom
110  // bindings.
111  int request_id = dispatcher_->request_sender()->GetNextRequestId();
112  dispatcher_->request_sender()->StartRequest(this, request_name, request_id,
113                                              false, false, &args);
114  return PP_OK;
115}
116
117int32_t PepperExtensionsCommonHost::OnCall(
118    ppapi::host::HostMessageContext* context,
119    const std::string& request_name,
120    base::ListValue& args) {
121  // TODO(yzshen): Add support for calling into JS for APIs that have custom
122  // bindings.
123  int request_id = dispatcher_->request_sender()->GetNextRequestId();
124  pending_request_map_[request_id] =
125      linked_ptr<ppapi::host::ReplyMessageContext>(
126          new ppapi::host::ReplyMessageContext(
127              context->MakeReplyMessageContext()));
128
129  dispatcher_->request_sender()->StartRequest(this, request_name, request_id,
130                                              true, false, &args);
131  return PP_OK_COMPLETIONPENDING;
132}
133
134}  // namespace chrome
135
136