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 "base/numerics/safe_conversions.h"
10 #include "build/build_config.h"
11 #include "ppapi/c/dev/ppp_printing_dev.h"
12 #include "ppapi/proxy/host_dispatcher.h"
13 #include "ppapi/proxy/plugin_dispatcher.h"
14 #include "ppapi/proxy/plugin_resource_tracker.h"
15 #include "ppapi/proxy/ppapi_messages.h"
16 #include "ppapi/shared_impl/ppapi_globals.h"
17 #include "ppapi/shared_impl/proxy_lock.h"
18 #include "ppapi/shared_impl/resource_tracker.h"
19 
20 namespace ppapi {
21 namespace proxy {
22 
23 namespace {
24 
25 #if !defined(OS_NACL)
HasPrintingPermission(PP_Instance instance)26 bool HasPrintingPermission(PP_Instance instance) {
27   Dispatcher* dispatcher = HostDispatcher::GetForInstance(instance);
28   if (!dispatcher)
29     return false;
30   return dispatcher->permissions().HasPermission(PERMISSION_DEV);
31 }
32 
QuerySupportedFormats(PP_Instance instance)33 uint32_t QuerySupportedFormats(PP_Instance instance) {
34   if (!HasPrintingPermission(instance))
35     return 0;
36   uint32_t result = 0;
37   HostDispatcher::GetForInstance(instance)->Send(
38       new PpapiMsg_PPPPrinting_QuerySupportedFormats(API_ID_PPP_PRINTING,
39                                                      instance, &result));
40   return result;
41 }
42 
Begin(PP_Instance instance,const PP_PrintSettings_Dev * print_settings)43 int32_t Begin(PP_Instance instance,
44               const PP_PrintSettings_Dev* print_settings) {
45   if (!HasPrintingPermission(instance))
46     return 0;
47 
48   int32_t result = 0;
49   HostDispatcher::GetForInstance(instance)->Send(new PpapiMsg_PPPPrinting_Begin(
50       API_ID_PPP_PRINTING, instance, *print_settings, &result));
51   return result;
52 }
53 
PrintPages(PP_Instance instance,const PP_PrintPageNumberRange_Dev * page_ranges,uint32_t page_range_count)54 PP_Resource PrintPages(PP_Instance instance,
55                        const PP_PrintPageNumberRange_Dev* page_ranges,
56                        uint32_t page_range_count) {
57   if (!HasPrintingPermission(instance))
58     return 0;
59   std::vector<PP_PrintPageNumberRange_Dev> pages(
60       page_ranges, page_ranges + page_range_count);
61 
62   HostResource result;
63   HostDispatcher::GetForInstance(instance)->Send(
64       new PpapiMsg_PPPPrinting_PrintPages(API_ID_PPP_PRINTING,
65                                           instance, pages, &result));
66 
67   // Explicilty don't add a reference to the received resource here. The plugin
68   // adds a ref during creation of the resource and it will "abandon" the
69   // resource to release it, which ensures that the initial ref won't be
70   // decremented. See the comment below in OnPluginMsgPrintPages.
71 
72   return result.host_resource();
73 }
74 
End(PP_Instance instance)75 void End(PP_Instance instance) {
76   if (!HasPrintingPermission(instance))
77     return;
78   HostDispatcher::GetForInstance(instance)->Send(
79       new PpapiMsg_PPPPrinting_End(API_ID_PPP_PRINTING, instance));
80 }
81 
IsScalingDisabled(PP_Instance instance)82 PP_Bool IsScalingDisabled(PP_Instance instance) {
83   if (!HasPrintingPermission(instance))
84     return PP_FALSE;
85   bool result = false;
86   HostDispatcher::GetForInstance(instance)->Send(
87       new PpapiMsg_PPPPrinting_IsScalingDisabled(API_ID_PPP_PRINTING,
88                                                  instance, &result));
89   return PP_FromBool(result);
90 }
91 
92 const PPP_Printing_Dev ppp_printing_interface = {
93   &QuerySupportedFormats,
94   &Begin,
95   &PrintPages,
96   &End,
97   &IsScalingDisabled
98 };
99 #else
100 // The NaCl plugin doesn't need the host side interface - stub it out.
101 static const PPP_Printing_Dev ppp_printing_interface = {};
102 #endif  // !defined(OS_NACL)
103 
104 }  // namespace
105 
PPP_Printing_Proxy(Dispatcher * dispatcher)106 PPP_Printing_Proxy::PPP_Printing_Proxy(Dispatcher* dispatcher)
107     : InterfaceProxy(dispatcher),
108       ppp_printing_impl_(NULL) {
109   if (dispatcher->IsPlugin()) {
110     ppp_printing_impl_ = static_cast<const PPP_Printing_Dev*>(
111         dispatcher->local_get_interface()(PPP_PRINTING_DEV_INTERFACE));
112   }
113 }
114 
~PPP_Printing_Proxy()115 PPP_Printing_Proxy::~PPP_Printing_Proxy() {
116 }
117 
118 // static
GetProxyInterface()119 const PPP_Printing_Dev* PPP_Printing_Proxy::GetProxyInterface() {
120   return &ppp_printing_interface;
121 }
122 
OnMessageReceived(const IPC::Message & msg)123 bool PPP_Printing_Proxy::OnMessageReceived(const IPC::Message& msg) {
124   if (!dispatcher()->IsPlugin())
125     return false;
126 
127   bool handled = true;
128   IPC_BEGIN_MESSAGE_MAP(PPP_Printing_Proxy, msg)
129     IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_QuerySupportedFormats,
130                         OnPluginMsgQuerySupportedFormats)
131     IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_Begin,
132                         OnPluginMsgBegin)
133     IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_PrintPages,
134                         OnPluginMsgPrintPages)
135     IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_End,
136                         OnPluginMsgEnd)
137     IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_IsScalingDisabled,
138                         OnPluginMsgIsScalingDisabled)
139     IPC_MESSAGE_UNHANDLED(handled = false)
140   IPC_END_MESSAGE_MAP()
141   return handled;
142 }
143 
OnPluginMsgQuerySupportedFormats(PP_Instance instance,uint32_t * result)144 void PPP_Printing_Proxy::OnPluginMsgQuerySupportedFormats(PP_Instance instance,
145                                                           uint32_t* result) {
146   if (ppp_printing_impl_) {
147     *result = CallWhileUnlocked(ppp_printing_impl_->QuerySupportedFormats,
148                                 instance);
149   } else {
150     *result = 0;
151   }
152 }
153 
OnPluginMsgBegin(PP_Instance instance,const PP_PrintSettings_Dev & settings,int32_t * result)154 void PPP_Printing_Proxy::OnPluginMsgBegin(PP_Instance instance,
155                                           const PP_PrintSettings_Dev& settings,
156                                           int32_t* result) {
157   if (!ppp_printing_impl_) {
158     *result = 0;
159     return;
160   }
161 
162   *result = CallWhileUnlocked(ppp_printing_impl_->Begin, instance, &settings);
163 }
164 
OnPluginMsgPrintPages(PP_Instance instance,const std::vector<PP_PrintPageNumberRange_Dev> & pages,HostResource * result)165 void PPP_Printing_Proxy::OnPluginMsgPrintPages(
166     PP_Instance instance,
167     const std::vector<PP_PrintPageNumberRange_Dev>& pages,
168     HostResource* result) {
169   if (!ppp_printing_impl_ || pages.empty())
170     return;
171 
172   PP_Resource plugin_resource = CallWhileUnlocked(
173       ppp_printing_impl_->PrintPages,
174       instance, &pages[0], base::checked_cast<uint32_t>(pages.size()));
175   ResourceTracker* resource_tracker = PpapiGlobals::Get()->GetResourceTracker();
176   Resource* resource_object = resource_tracker->GetResource(plugin_resource);
177   if (!resource_object)
178     return;
179 
180   *result = resource_object->host_resource();
181 
182   // Abandon the resource on the plugin side. This releases a reference to the
183   // resource and allows the plugin side of the resource (the proxy resource) to
184   // be destroyed without sending a message to the renderer notifing it that the
185   // plugin has released the resource. This used to call
186   // ResourceTracker::ReleaseResource directly which would trigger an IPC to be
187   // sent to the renderer to remove a ref to the resource. However due to
188   // arbitrary ordering of received sync/async IPCs in the renderer, this
189   // sometimes resulted in the resource being destroyed in the renderer before
190   // the renderer had a chance to add a reference to it. See crbug.com/490611.
191   static_cast<PluginResourceTracker*>(resource_tracker)
192       ->AbandonResource(plugin_resource);
193 }
194 
OnPluginMsgEnd(PP_Instance instance)195 void PPP_Printing_Proxy::OnPluginMsgEnd(PP_Instance instance) {
196   if (ppp_printing_impl_)
197     CallWhileUnlocked(ppp_printing_impl_->End, instance);
198 }
199 
OnPluginMsgIsScalingDisabled(PP_Instance instance,bool * result)200 void 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