Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / renderer_host / pepper / pepper_output_protection_message_filter.cc
1 // Copyright 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/browser/renderer_host/pepper/pepper_output_protection_message_filter.h"
6
7 #include "build/build_config.h"
8 #include "chrome/browser/media/media_capture_devices_dispatcher.h"
9 #include "content/public/browser/browser_ppapi_host.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/browser/render_frame_host.h"
12 #include "content/public/browser/web_contents.h"
13 #include "ppapi/c/pp_errors.h"
14 #include "ppapi/c/private/ppb_output_protection_private.h"
15 #include "ppapi/host/dispatch_host_message.h"
16 #include "ppapi/host/host_message_context.h"
17 #include "ppapi/host/ppapi_host.h"
18 #include "ppapi/proxy/ppapi_messages.h"
19
20 #if defined(OS_CHROMEOS)
21 #include "ash/shell.h"
22 #include "ash/shell_delegate.h"
23 #include "chromeos/display/output_configurator.h"
24 #include "ui/aura/window.h"
25 #include "ui/gfx/screen.h"
26 #endif
27
28 namespace chrome {
29
30 namespace {
31
32 #if defined(OS_CHROMEOS)
33 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE) ==
34                    static_cast<int>(ui::OUTPUT_TYPE_NONE),
35                PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE);
36 COMPILE_ASSERT(
37     static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN) ==
38         static_cast<int>(ui::OUTPUT_TYPE_UNKNOWN),
39     PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_UNKNOWN);
40 COMPILE_ASSERT(
41     static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL) ==
42         static_cast<int>(ui::OUTPUT_TYPE_INTERNAL),
43     PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL);
44 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA) ==
45                    static_cast<int>(ui::OUTPUT_TYPE_VGA),
46                PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA);
47 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI) ==
48                    static_cast<int>(ui::OUTPUT_TYPE_HDMI),
49                PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI);
50 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI) ==
51                    static_cast<int>(ui::OUTPUT_TYPE_DVI),
52                PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DVI);
53 COMPILE_ASSERT(
54     static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT) ==
55         static_cast<int>(ui::OUTPUT_TYPE_DISPLAYPORT),
56     PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT);
57 COMPILE_ASSERT(
58     static_cast<int>(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK) ==
59         static_cast<int>(ui::OUTPUT_TYPE_NETWORK),
60     PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NETWORK);
61 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE) ==
62                    static_cast<int>(ui::OUTPUT_PROTECTION_METHOD_NONE),
63                PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE);
64 COMPILE_ASSERT(static_cast<int>(PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP) ==
65                    static_cast<int>(ui::OUTPUT_PROTECTION_METHOD_HDCP),
66                PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP);
67
68 bool GetCurrentDisplayId(content::RenderFrameHost* rfh, int64* display_id) {
69   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
70   gfx::NativeView native_view = rfh->GetNativeView();
71   gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view);
72   if (!screen)
73     return false;
74   gfx::Display display = screen->GetDisplayNearestWindow(native_view);
75   *display_id = display.id();
76   return true;
77 }
78 #endif
79
80 }  // namespace
81
82 #if defined(OS_CHROMEOS)
83 // Output protection delegate. All methods except constructor should be
84 // invoked in UI thread.
85 class PepperOutputProtectionMessageFilter::Delegate
86     : public aura::WindowObserver {
87  public:
88   Delegate(int render_process_id, int render_frame_id);
89   virtual ~Delegate();
90
91   // aura::WindowObserver overrides.
92   virtual void OnWindowHierarchyChanged(
93       const aura::WindowObserver::HierarchyChangeParams& params) OVERRIDE;
94
95   int32_t OnQueryStatus(uint32_t* link_mask, uint32_t* protection_mask);
96   int32_t OnEnableProtection(uint32_t desired_method_mask);
97
98  private:
99   chromeos::OutputConfigurator::OutputProtectionClientId GetClientId();
100
101   // Used to lookup the WebContents associated with this PP_Instance.
102   int render_process_id_;
103   int render_frame_id_;
104
105   chromeos::OutputConfigurator::OutputProtectionClientId client_id_;
106   // The display id which the renderer currently uses.
107   int64 display_id_;
108   // The last desired method mask. Will enable this mask on new display if
109   // renderer changes display.
110   uint32_t desired_method_mask_;
111 };
112
113 PepperOutputProtectionMessageFilter::Delegate::Delegate(int render_process_id,
114                                                         int render_frame_id)
115     : render_process_id_(render_process_id),
116       render_frame_id_(render_frame_id),
117       client_id_(chromeos::OutputConfigurator::kInvalidClientId),
118       display_id_(0) {
119   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
120
121 }
122
123 PepperOutputProtectionMessageFilter::Delegate::~Delegate() {
124   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
125
126   chromeos::OutputConfigurator* configurator =
127       ash::Shell::GetInstance()->output_configurator();
128   configurator->UnregisterOutputProtectionClient(client_id_);
129
130   content::RenderFrameHost* rfh =
131       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
132   if (rfh) {
133     gfx::NativeView native_view = rfh->GetNativeView();
134     if (native_view)
135       native_view->RemoveObserver(this);
136   }
137 }
138
139 chromeos::OutputConfigurator::OutputProtectionClientId
140 PepperOutputProtectionMessageFilter::Delegate::GetClientId() {
141   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
142   if (client_id_ == chromeos::OutputConfigurator::kInvalidClientId) {
143     content::RenderFrameHost* rfh =
144         content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
145     if (!GetCurrentDisplayId(rfh, &display_id_))
146       return chromeos::OutputConfigurator::kInvalidClientId;
147     gfx::NativeView native_view = rfh->GetNativeView();
148     if (!native_view)
149       return chromeos::OutputConfigurator::kInvalidClientId;
150     native_view->AddObserver(this);
151
152     chromeos::OutputConfigurator* configurator =
153         ash::Shell::GetInstance()->output_configurator();
154     client_id_ = configurator->RegisterOutputProtectionClient();
155   }
156   return client_id_;
157 }
158
159 int32_t PepperOutputProtectionMessageFilter::Delegate::OnQueryStatus(
160     uint32_t* link_mask, uint32_t* protection_mask) {
161   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
162
163   content::RenderFrameHost* rfh =
164       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
165   if (!rfh) {
166     LOG(WARNING) << "RenderFrameHost is not alive.";
167     return PP_ERROR_FAILED;
168   }
169
170   chromeos::OutputConfigurator* configurator =
171       ash::Shell::GetInstance()->output_configurator();
172   bool result = configurator->QueryOutputProtectionStatus(
173       GetClientId(), display_id_, link_mask, protection_mask);
174
175   // If we successfully retrieved the device level status, check for capturers.
176   if (result) {
177     const bool capture_detected =
178         // Check for tab capture on the current tab.
179         content::WebContents::FromRenderFrameHost(rfh)->
180             GetCapturerCount() > 0 ||
181         // Check for desktop capture.
182         MediaCaptureDevicesDispatcher::GetInstance()
183             ->IsDesktopCaptureInProgress();
184     if (capture_detected)
185       *link_mask |= ui::OUTPUT_TYPE_NETWORK;
186   }
187
188   return result ? PP_OK : PP_ERROR_FAILED;
189 }
190
191 int32_t PepperOutputProtectionMessageFilter::Delegate::OnEnableProtection(
192     uint32_t desired_method_mask) {
193   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
194
195   chromeos::OutputConfigurator* configurator =
196       ash::Shell::GetInstance()->output_configurator();
197   bool result = configurator->EnableOutputProtection(
198       GetClientId(), display_id_, desired_method_mask);
199   desired_method_mask_ = desired_method_mask;
200   return result ? PP_OK : PP_ERROR_FAILED;
201 }
202
203 void PepperOutputProtectionMessageFilter::Delegate::OnWindowHierarchyChanged(
204     const aura::WindowObserver::HierarchyChangeParams& params) {
205   content::RenderFrameHost* rfh =
206       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
207   if (!rfh) {
208     LOG(WARNING) << "RenderFrameHost is not alive.";
209     return;
210   }
211
212   int64 new_display_id = 0;
213   if (!GetCurrentDisplayId(rfh, &new_display_id))
214     return;
215   if (display_id_ == new_display_id)
216     return;
217
218   if (desired_method_mask_ != ui::OUTPUT_PROTECTION_METHOD_NONE) {
219     // Display changed and should enable output protections on new display.
220     chromeos::OutputConfigurator* configurator =
221         ash::Shell::GetInstance()->output_configurator();
222     configurator->EnableOutputProtection(GetClientId(), new_display_id,
223                                          desired_method_mask_);
224     configurator->EnableOutputProtection(
225         GetClientId(), display_id_, ui::OUTPUT_PROTECTION_METHOD_NONE);
226   }
227   display_id_ = new_display_id;
228 }
229 #endif
230
231 PepperOutputProtectionMessageFilter::PepperOutputProtectionMessageFilter(
232     content::BrowserPpapiHost* host,
233     PP_Instance instance) {
234 #if defined(OS_CHROMEOS)
235   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
236   int render_process_id = 0;
237   int render_frame_id = 0;
238   host->GetRenderFrameIDsForInstance(
239       instance, &render_process_id, &render_frame_id);
240   delegate_ = new Delegate(render_process_id, render_frame_id);
241 #else
242   NOTIMPLEMENTED();
243 #endif
244 }
245
246 PepperOutputProtectionMessageFilter::~PepperOutputProtectionMessageFilter() {
247 #if defined(OS_CHROMEOS)
248   content::BrowserThread::DeleteSoon(content::BrowserThread::UI, FROM_HERE,
249                                      delegate_);
250   delegate_ = NULL;
251 #endif
252 }
253
254 scoped_refptr<base::TaskRunner>
255 PepperOutputProtectionMessageFilter::OverrideTaskRunnerForMessage(
256     const IPC::Message& message) {
257   return content::BrowserThread::GetMessageLoopProxyForThread(
258       content::BrowserThread::UI);
259 }
260
261 int32_t PepperOutputProtectionMessageFilter::OnResourceMessageReceived(
262     const IPC::Message& msg,
263     ppapi::host::HostMessageContext* context) {
264   IPC_BEGIN_MESSAGE_MAP(PepperOutputProtectionMessageFilter, msg)
265     PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
266         PpapiHostMsg_OutputProtection_QueryStatus,
267         OnQueryStatus);
268     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
269         PpapiHostMsg_OutputProtection_EnableProtection,
270         OnEnableProtection);
271   IPC_END_MESSAGE_MAP()
272   return PP_ERROR_FAILED;
273 }
274
275 int32_t PepperOutputProtectionMessageFilter::OnQueryStatus(
276     ppapi::host::HostMessageContext* context) {
277 #if defined(OS_CHROMEOS)
278   uint32_t link_mask = 0, protection_mask = 0;
279   int32_t result = delegate_->OnQueryStatus(&link_mask, &protection_mask);
280
281   ppapi::host::ReplyMessageContext reply_context =
282       context->MakeReplyMessageContext();
283   reply_context.params.set_result(result);
284   SendReply(
285       reply_context,
286       PpapiPluginMsg_OutputProtection_QueryStatusReply(
287           link_mask, protection_mask));
288   return PP_OK_COMPLETIONPENDING;
289 #else
290   NOTIMPLEMENTED();
291   return PP_ERROR_NOTSUPPORTED;
292 #endif
293 }
294
295 int32_t PepperOutputProtectionMessageFilter::OnEnableProtection(
296     ppapi::host::HostMessageContext* context,
297     uint32_t desired_method_mask) {
298 #if defined(OS_CHROMEOS)
299   ppapi::host::ReplyMessageContext reply_context =
300       context->MakeReplyMessageContext();
301   int32_t result = delegate_->OnEnableProtection(desired_method_mask);
302   reply_context.params.set_result(result);
303   SendReply(
304       reply_context,
305       PpapiPluginMsg_OutputProtection_EnableProtectionReply());
306   return PP_OK_COMPLETIONPENDING;
307 #else
308   NOTIMPLEMENTED();
309   return PP_ERROR_NOTSUPPORTED;
310 #endif
311 }
312
313 }  // namespace chrome
314