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.
5 #include "ppapi/proxy/ppp_printing_proxy.h"
9 #include "base/numerics/safe_conversions.h"
10 #include "ppapi/c/dev/ppp_printing_dev.h"
11 #include "ppapi/proxy/host_dispatcher.h"
12 #include "ppapi/proxy/plugin_dispatcher.h"
13 #include "ppapi/proxy/plugin_resource_tracker.h"
14 #include "ppapi/proxy/ppapi_messages.h"
15 #include "ppapi/shared_impl/ppapi_globals.h"
16 #include "ppapi/shared_impl/proxy_lock.h"
17 #include "ppapi/shared_impl/resource_tracker.h"
25 bool HasPrintingPermission(PP_Instance instance
) {
26 Dispatcher
* dispatcher
= HostDispatcher::GetForInstance(instance
);
29 return dispatcher
->permissions().HasPermission(PERMISSION_DEV
);
32 uint32_t QuerySupportedFormats(PP_Instance instance
) {
33 if (!HasPrintingPermission(instance
))
36 HostDispatcher::GetForInstance(instance
)->Send(
37 new PpapiMsg_PPPPrinting_QuerySupportedFormats(API_ID_PPP_PRINTING
,
42 int32_t Begin(PP_Instance instance
,
43 const struct PP_PrintSettings_Dev
* print_settings
) {
44 if (!HasPrintingPermission(instance
))
46 // Settings is just serialized as a string.
47 std::string settings_string
;
48 settings_string
.resize(sizeof(*print_settings
));
49 memcpy(&settings_string
[0], print_settings
, sizeof(*print_settings
));
52 HostDispatcher::GetForInstance(instance
)->Send(
53 new PpapiMsg_PPPPrinting_Begin(API_ID_PPP_PRINTING
, instance
,
54 settings_string
, &result
));
58 PP_Resource
PrintPages(PP_Instance instance
,
59 const PP_PrintPageNumberRange_Dev
* page_ranges
,
60 uint32_t page_range_count
) {
61 if (!HasPrintingPermission(instance
))
63 std::vector
<PP_PrintPageNumberRange_Dev
> pages(
64 page_ranges
, page_ranges
+ page_range_count
);
67 HostDispatcher::GetForInstance(instance
)->Send(
68 new PpapiMsg_PPPPrinting_PrintPages(API_ID_PPP_PRINTING
,
69 instance
, pages
, &result
));
71 // Explicilty don't add a reference to the received resource here. The plugin
72 // adds a ref during creation of the resource and it will "abandon" the
73 // resource to release it, which ensures that the initial ref won't be
74 // decremented. See the comment below in OnPluginMsgPrintPages.
76 return result
.host_resource();
79 void End(PP_Instance instance
) {
80 if (!HasPrintingPermission(instance
))
82 HostDispatcher::GetForInstance(instance
)->Send(
83 new PpapiMsg_PPPPrinting_End(API_ID_PPP_PRINTING
, instance
));
86 PP_Bool
IsScalingDisabled(PP_Instance instance
) {
87 if (!HasPrintingPermission(instance
))
90 HostDispatcher::GetForInstance(instance
)->Send(
91 new PpapiMsg_PPPPrinting_IsScalingDisabled(API_ID_PPP_PRINTING
,
93 return PP_FromBool(result
);
96 const PPP_Printing_Dev ppp_printing_interface
= {
97 &QuerySupportedFormats
,
104 // The NaCl plugin doesn't need the host side interface - stub it out.
105 static const PPP_Printing_Dev ppp_printing_interface
= {};
106 #endif // !defined(OS_NACL)
110 PPP_Printing_Proxy::PPP_Printing_Proxy(Dispatcher
* dispatcher
)
111 : InterfaceProxy(dispatcher
),
112 ppp_printing_impl_(NULL
) {
113 if (dispatcher
->IsPlugin()) {
114 ppp_printing_impl_
= static_cast<const PPP_Printing_Dev
*>(
115 dispatcher
->local_get_interface()(PPP_PRINTING_DEV_INTERFACE
));
119 PPP_Printing_Proxy::~PPP_Printing_Proxy() {
123 const PPP_Printing_Dev
* PPP_Printing_Proxy::GetProxyInterface() {
124 return &ppp_printing_interface
;
127 bool PPP_Printing_Proxy::OnMessageReceived(const IPC::Message
& msg
) {
128 if (!dispatcher()->IsPlugin())
132 IPC_BEGIN_MESSAGE_MAP(PPP_Printing_Proxy
, msg
)
133 IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_QuerySupportedFormats
,
134 OnPluginMsgQuerySupportedFormats
)
135 IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_Begin
,
137 IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_PrintPages
,
138 OnPluginMsgPrintPages
)
139 IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_End
,
141 IPC_MESSAGE_HANDLER(PpapiMsg_PPPPrinting_IsScalingDisabled
,
142 OnPluginMsgIsScalingDisabled
)
143 IPC_MESSAGE_UNHANDLED(handled
= false)
144 IPC_END_MESSAGE_MAP()
148 void PPP_Printing_Proxy::OnPluginMsgQuerySupportedFormats(PP_Instance instance
,
150 if (ppp_printing_impl_
) {
151 *result
= CallWhileUnlocked(ppp_printing_impl_
->QuerySupportedFormats
,
158 void PPP_Printing_Proxy::OnPluginMsgBegin(PP_Instance instance
,
159 const std::string
& settings_string
,
163 PP_PrintSettings_Dev settings
;
164 if (settings_string
.size() != sizeof(settings
))
166 memcpy(&settings
, &settings_string
[0], sizeof(settings
));
168 if (ppp_printing_impl_
)
169 *result
= CallWhileUnlocked(ppp_printing_impl_
->Begin
, instance
, &settings
);
172 void PPP_Printing_Proxy::OnPluginMsgPrintPages(
173 PP_Instance instance
,
174 const std::vector
<PP_PrintPageNumberRange_Dev
>& pages
,
175 HostResource
* result
) {
176 if (!ppp_printing_impl_
|| pages
.empty())
179 PP_Resource plugin_resource
= CallWhileUnlocked(
180 ppp_printing_impl_
->PrintPages
,
181 instance
, &pages
[0], base::checked_cast
<uint32_t>(pages
.size()));
182 ResourceTracker
* resource_tracker
= PpapiGlobals::Get()->GetResourceTracker();
183 Resource
* resource_object
= resource_tracker
->GetResource(plugin_resource
);
184 if (!resource_object
)
187 *result
= resource_object
->host_resource();
189 // Abandon the resource on the plugin side. This releases a reference to the
190 // resource and allows the plugin side of the resource (the proxy resource) to
191 // be destroyed without sending a message to the renderer notifing it that the
192 // plugin has released the resource. This used to call
193 // ResourceTracker::ReleaseResource directly which would trigger an IPC to be
194 // sent to the renderer to remove a ref to the resource. However due to
195 // arbitrary ordering of received sync/async IPCs in the renderer, this
196 // sometimes resulted in the resource being destroyed in the renderer before
197 // the renderer had a chance to add a reference to it. See crbug.com/490611.
198 static_cast<PluginResourceTracker
*>(resource_tracker
)
199 ->AbandonResource(plugin_resource
);
202 void PPP_Printing_Proxy::OnPluginMsgEnd(PP_Instance instance
) {
203 if (ppp_printing_impl_
)
204 CallWhileUnlocked(ppp_printing_impl_
->End
, instance
);
207 void PPP_Printing_Proxy::OnPluginMsgIsScalingDisabled(PP_Instance instance
,
209 if (ppp_printing_impl_
) {
210 *result
= PP_ToBool(CallWhileUnlocked(ppp_printing_impl_
->IsScalingDisabled
,