Upstream version 7.36.149.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 "ui/aura/window.h"
24 #include "ui/display/chromeos/display_configurator.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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::DISPLAY_CONNECTION_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::CONTENT_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::CONTENT_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   ui::DisplayConfigurator::ContentProtectionClientId 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   ui::DisplayConfigurator::ContentProtectionClientId 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_(ui::DisplayConfigurator::kInvalidClientId),
118       display_id_(0) {
119   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
120 }
121
122 PepperOutputProtectionMessageFilter::Delegate::~Delegate() {
123   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
124
125   ui::DisplayConfigurator* configurator =
126       ash::Shell::GetInstance()->display_configurator();
127   configurator->UnregisterContentProtectionClient(client_id_);
128
129   content::RenderFrameHost* rfh =
130       content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
131   if (rfh) {
132     gfx::NativeView native_view = rfh->GetNativeView();
133     if (native_view)
134       native_view->RemoveObserver(this);
135   }
136 }
137
138 ui::DisplayConfigurator::ContentProtectionClientId
139 PepperOutputProtectionMessageFilter::Delegate::GetClientId() {
140   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
141   if (client_id_ == ui::DisplayConfigurator::kInvalidClientId) {
142     content::RenderFrameHost* rfh =
143         content::RenderFrameHost::FromID(render_process_id_, render_frame_id_);
144     if (!GetCurrentDisplayId(rfh, &display_id_))
145       return ui::DisplayConfigurator::kInvalidClientId;
146     gfx::NativeView native_view = rfh->GetNativeView();
147     if (!native_view)
148       return ui::DisplayConfigurator::kInvalidClientId;
149     native_view->AddObserver(this);
150
151     ui::DisplayConfigurator* configurator =
152         ash::Shell::GetInstance()->display_configurator();
153     client_id_ = configurator->RegisterContentProtectionClient();
154   }
155   return client_id_;
156 }
157
158 int32_t PepperOutputProtectionMessageFilter::Delegate::OnQueryStatus(
159     uint32_t* link_mask,
160     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   ui::DisplayConfigurator* configurator =
171       ash::Shell::GetInstance()->display_configurator();
172   bool result = configurator->QueryContentProtectionStatus(
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)->GetCapturerCount() >
180             0 ||
181         // Check for desktop capture.
182         MediaCaptureDevicesDispatcher::GetInstance()
183             ->IsDesktopCaptureInProgress();
184     if (capture_detected)
185       *link_mask |= ui::DISPLAY_CONNECTION_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   ui::DisplayConfigurator* configurator =
196       ash::Shell::GetInstance()->display_configurator();
197   bool result = configurator->EnableContentProtection(
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::CONTENT_PROTECTION_METHOD_NONE) {
219     // Display changed and should enable output protections on new display.
220     ui::DisplayConfigurator* configurator =
221         ash::Shell::GetInstance()->display_configurator();
222     configurator->EnableContentProtection(
223         GetClientId(), new_display_id, desired_method_mask_);
224     configurator->EnableContentProtection(
225         GetClientId(), display_id_, ui::CONTENT_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(
249       content::BrowserThread::UI, FROM_HERE, 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(PpapiHostMsg_OutputProtection_QueryStatus,
266                                       OnQueryStatus);
267   PPAPI_DISPATCH_HOST_RESOURCE_CALL(
268       PpapiHostMsg_OutputProtection_EnableProtection, OnEnableProtection);
269   IPC_END_MESSAGE_MAP()
270   return PP_ERROR_FAILED;
271 }
272
273 int32_t PepperOutputProtectionMessageFilter::OnQueryStatus(
274     ppapi::host::HostMessageContext* context) {
275 #if defined(OS_CHROMEOS)
276   uint32_t link_mask = 0, protection_mask = 0;
277   int32_t result = delegate_->OnQueryStatus(&link_mask, &protection_mask);
278
279   ppapi::host::ReplyMessageContext reply_context =
280       context->MakeReplyMessageContext();
281   reply_context.params.set_result(result);
282   SendReply(reply_context,
283             PpapiPluginMsg_OutputProtection_QueryStatusReply(link_mask,
284                                                              protection_mask));
285   return PP_OK_COMPLETIONPENDING;
286 #else
287   NOTIMPLEMENTED();
288   return PP_ERROR_NOTSUPPORTED;
289 #endif
290 }
291
292 int32_t PepperOutputProtectionMessageFilter::OnEnableProtection(
293     ppapi::host::HostMessageContext* context,
294     uint32_t desired_method_mask) {
295 #if defined(OS_CHROMEOS)
296   ppapi::host::ReplyMessageContext reply_context =
297       context->MakeReplyMessageContext();
298   int32_t result = delegate_->OnEnableProtection(desired_method_mask);
299   reply_context.params.set_result(result);
300   SendReply(reply_context,
301             PpapiPluginMsg_OutputProtection_EnableProtectionReply());
302   return PP_OK_COMPLETIONPENDING;
303 #else
304   NOTIMPLEMENTED();
305   return PP_ERROR_NOTSUPPORTED;
306 #endif
307 }
308
309 }  // namespace chrome