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 "ppapi/proxy/ppp_printing_proxy.h"
6
7#include <string.h>
8
9#include "ppapi/c/dev/ppp_printing_dev.h"
10#include "ppapi/proxy/host_dispatcher.h"
11#include "ppapi/proxy/plugin_dispatcher.h"
12#include "ppapi/proxy/ppapi_messages.h"
13#include "ppapi/shared_impl/ppapi_globals.h"
14#include "ppapi/shared_impl/proxy_lock.h"
15#include "ppapi/shared_impl/resource_tracker.h"
16
17namespace ppapi {
18namespace proxy {
19
20namespace {
21
22#if !defined(OS_NACL)
23bool HasPrintingPermission(PP_Instance instance) {
24  Dispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
25  if (!dispatcher)
26    return false;
27  return dispatcher->permissions().HasPermission(PERMISSION_DEV);
28}
29
30uint32_t QuerySupportedFormats(PP_Instance instance) {
31  if (!HasPrintingPermission(instance))
32    return 0;
33  uint32_t result = 0;
34  HostDispatcher::GetForInstance(instance)->Send(
35      new PpapiMsg_PPPPrinting_QuerySupportedFormats(API_ID_PPP_PRINTING,
36                                                     instance, &result));
37  return result;
38}
39
40int32_t Begin(PP_Instance instance,
41              const struct PP_PrintSettings_Dev* print_settings) {
42  if (!HasPrintingPermission(instance))
43    return 0;
44  // Settings is just serialized as a string.
45  std::string settings_string;
46  settings_string.resize(sizeof(*print_settings));
47  memcpy(&settings_string[0], print_settings, sizeof(*print_settings));
48
49  int32_t result = 0;
50  HostDispatcher::GetForInstance(instance)->Send(
51      new PpapiMsg_PPPPrinting_Begin(API_ID_PPP_PRINTING, instance,
52                                     settings_string, &result));
53  return result;
54}
55
56PP_Resource PrintPages(PP_Instance instance,
57                       const PP_PrintPageNumberRange_Dev* page_ranges,
58                       uint32_t page_range_count) {
59  if (!HasPrintingPermission(instance))
60    return 0;
61  std::vector<PP_PrintPageNumberRange_Dev> pages(
62      page_ranges, page_ranges + page_range_count);
63
64  HostResource result;
65  HostDispatcher::GetForInstance(instance)->Send(
66      new PpapiMsg_PPPPrinting_PrintPages(API_ID_PPP_PRINTING,
67                                          instance, pages, &result));
68
69  // How refcounting works when returning a resource:
70  //
71  // The plugin in the plugin process makes a resource that it returns to the
72  // browser. The plugin proxy code returns that ref to us and asynchronously
73  // releases it. Before any release message associated with that operation
74  // comes, we'll get this reply. We need to add one ref since our caller
75  // expects us to add one ref for it to consume.
76  PpapiGlobals::Get()->GetResourceTracker()->AddRefResource(
77      result.host_resource());
78  return result.host_resource();
79}
80
81void End(PP_Instance instance) {
82  if (!HasPrintingPermission(instance))
83    return;
84  HostDispatcher::GetForInstance(instance)->Send(
85      new PpapiMsg_PPPPrinting_End(API_ID_PPP_PRINTING, instance));
86}
87
88PP_Bool IsScalingDisabled(PP_Instance instance) {
89  if (!HasPrintingPermission(instance))
90    return PP_FALSE;
91  bool result = false;
92  HostDispatcher::GetForInstance(instance)->Send(
93      new PpapiMsg_PPPPrinting_IsScalingDisabled(API_ID_PPP_PRINTING,
94                                                 instance, &result));
95  return PP_FromBool(result);
96}
97
98const PPP_Printing_Dev ppp_printing_interface = {
99  &QuerySupportedFormats,
100  &Begin,
101  &PrintPages,
102  &End,
103  &IsScalingDisabled
104};
105#else
106// The NaCl plugin doesn't need the host side interface - stub it out.
107static const PPP_Printing_Dev ppp_printing_interface = {};
108#endif  // !defined(OS_NACL)
109
110}  // namespace
111
112PPP_Printing_Proxy::PPP_Printing_Proxy(Dispatcher* dispatcher)
113    : InterfaceProxy(dispatcher),
114      ppp_printing_impl_(NULL) {
115  if (dispatcher->IsPlugin()) {
116    ppp_printing_impl_ = static_cast<const PPP_Printing_Dev*>(
117        dispatcher->local_get_interface()(PPP_PRINTING_DEV_INTERFACE));
118  }
119}
120
121PPP_Printing_Proxy::~PPP_Printing_Proxy() {
122}
123
124// static
125const PPP_Printing_Dev* PPP_Printing_Proxy::GetProxyInterface() {
126  return &ppp_printing_interface;
127}
128
129bool PPP_Printing_Proxy::OnMessageReceived(const IPC::Message& msg) {
130  if (!dispatcher()->IsPlugin())
131    return false;
132
133  bool handled = true;
134  IPC_BEGIN_MESSAGE_MAP(PPP_Printing_Proxy, msg)
135    IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_QuerySupportedFormats,
136                        OnPluginMsgQuerySupportedFormats)
137    IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_Begin,
138                        OnPluginMsgBegin)
139    IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_PrintPages,
140                        OnPluginMsgPrintPages)
141    IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_End,
142                        OnPluginMsgEnd)
143    IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_IsScalingDisabled,
144                        OnPluginMsgIsScalingDisabled)
145    IPC_MESSAGE_UNHANDLED(handled = false)
146  IPC_END_MESSAGE_MAP()
147  return handled;
148}
149
150void PPP_Printing_Proxy::OnPluginMsgQuerySupportedFormats(PP_Instance instance,
151                                                          uint32_t* result) {
152  if (ppp_printing_impl_) {
153    *result = CallWhileUnlocked(ppp_printing_impl_->QuerySupportedFormats,
154                                instance);
155  } else {
156    *result = 0;
157  }
158}
159
160void PPP_Printing_Proxy::OnPluginMsgBegin(PP_Instance instance,
161                                          const std::string& settings_string,
162                                          int32_t* result) {
163  *result = 0;
164
165  PP_PrintSettings_Dev settings;
166  if (settings_string.size() != sizeof(settings))
167    return;
168  memcpy(&settings, &settings_string[0], sizeof(settings));
169
170  if (ppp_printing_impl_)
171    *result = CallWhileUnlocked(ppp_printing_impl_->Begin, instance, &settings);
172}
173
174void PPP_Printing_Proxy::OnPluginMsgPrintPages(
175    PP_Instance instance,
176    const std::vector<PP_PrintPageNumberRange_Dev>& pages,
177    HostResource* result) {
178  if (!ppp_printing_impl_ || pages.empty())
179    return;
180
181  PP_Resource plugin_resource = CallWhileUnlocked(
182      ppp_printing_impl_->PrintPages,
183      instance, &pages[0], pages.size());
184  ResourceTracker* resource_tracker = PpapiGlobals::Get()->GetResourceTracker();
185  Resource* resource_object = resource_tracker->GetResource(plugin_resource);
186  if (!resource_object)
187    return;
188
189  *result = resource_object->host_resource();
190
191  // See PrintPages above for how refcounting works.
192  resource_tracker->ReleaseResourceSoon(plugin_resource);
193}
194
195void PPP_Printing_Proxy::OnPluginMsgEnd(PP_Instance instance) {
196  if (ppp_printing_impl_)
197    CallWhileUnlocked(ppp_printing_impl_->End, instance);
198}
199
200void PPP_Printing_Proxy::OnPluginMsgIsScalingDisabled(PP_Instance instance,
201                                                      bool* result) {
202  if (ppp_printing_impl_) {
203    *result = PP_ToBool(CallWhileUnlocked(ppp_printing_impl_->IsScalingDisabled,
204                                          instance));
205  } else {
206    *result = false;
207  }
208}
209
210}  // namespace proxy
211}  // namespace ppapi
212