Chromium Code Reviews| Index: chromeos/display/real_output_configurator_delegate.cc |
| diff --git a/chromeos/display/real_output_configurator_delegate.cc b/chromeos/display/real_output_configurator_delegate.cc |
| index 43b4cdb5636b5f88746204f87bf902b538af3d27..d1a2ed7e3dd4df4f9fe201b283aceb284a7c91b8 100644 |
| --- a/chromeos/display/real_output_configurator_delegate.cc |
| +++ b/chromeos/display/real_output_configurator_delegate.cc |
| @@ -20,6 +20,7 @@ |
| #include "chromeos/dbus/dbus_thread_manager.h" |
| #include "chromeos/dbus/power_manager_client.h" |
| #include "chromeos/display/output_util.h" |
| +#include "ui/base/x/x11_error_tracker.h" |
| namespace chromeos { |
| @@ -30,6 +31,12 @@ const float kMmInInch = 25.4; |
| const float kDpi96 = 96.0; |
| const float kPixelsToMmScale = kMmInInch / kDpi96; |
| +// Prefixes of output name |
| +const char kOutputName_VGA[] = "VGA"; |
| +const char kOutputName_HDMI[] = "HDMI"; |
| +const char kOutputName_DVI[] = "DVI"; |
| +const char kOutputName_DisplayPort[] = "DP"; |
| + |
| bool IsInternalOutput(const XRROutputInfo* output_info) { |
| return IsInternalOutputName(std::string(output_info->name)); |
| } |
| @@ -306,6 +313,187 @@ RealOutputConfiguratorDelegate::InitOutputSnapshot( |
| return output; |
| } |
| +bool RealOutputConfiguratorDelegate::GetHDCPState(RROutput id, |
| + HDCPState* state) { |
| + CHECK(screen_) << "Server not grabbed"; |
| + unsigned char* values = NULL; |
| + int actual_format = 0; |
| + unsigned long nitems = 0; |
| + unsigned long bytes_after = 0; |
| + Atom actual_type = None; |
| + int success = 0; |
| + Atom prop = XInternAtom(display_, "Content Protection", False); |
|
Daniel Erat
2013/09/20 15:00:24
please move this to a constant at the top of the f
kcwu
2013/09/20 20:29:30
Done.
|
| + |
| + bool ok = true; |
| + // TODO(kcwu): Move this to x11_util (similar method calls in this file and |
| + // output_util.cc) |
| + success = XRRGetOutputProperty(display_, id, prop, 0, 100, False, |
| + False, AnyPropertyType, &actual_type, |
| + &actual_format, &nitems, &bytes_after, |
| + &values); |
| + if (actual_type == None) { |
| + LOG(ERROR) << "Property 'Content Protection' does not exist"; |
| + ok = false; |
| + } else if (success == Success && actual_type == XA_ATOM && |
| + actual_format == 32 && nitems == 1) { |
| + Atom value = reinterpret_cast<Atom*>(values)[0]; |
| + if (value == XInternAtom(display_, "Undesired", False)) { |
|
Daniel Erat
2013/09/20 15:00:24
please make constants for these too so they aren't
kcwu
2013/09/20 20:29:30
Done.
|
| + *state = HDCP_STATE_UNDESIRED; |
| + } else if (value == XInternAtom(display_, "Desired", False)) { |
| + *state = HDCP_STATE_DESIRED; |
| + } else if (value == XInternAtom(display_, "Enabled", False)) { |
| + *state = HDCP_STATE_ENABLED; |
| + } else { |
| + LOG(ERROR) << "Unknown property value: " << value; |
|
Daniel Erat
2013/09/20 15:00:24
nit: mind changing this to "Unknown " << kContentP
kcwu
2013/09/20 20:29:30
Done.
|
| + ok = false; |
| + } |
| + } else { |
| + LOG(ERROR) << "XRRGetOutputProperty failed"; |
| + ok = false; |
| + } |
| + if (values) |
| + XFree(values); |
| + |
| + VLOG(3) << "HDCP state: " << ok << "," << *state; |
| + return ok; |
| +} |
| + |
| +bool RealOutputConfiguratorDelegate::SetHDCPState(RROutput id, |
| + HDCPState state) { |
| + CHECK(screen_) << "Server not grabbed"; |
| + Atom name = XInternAtom(display_, "Content Protection", False); |
| + Atom value; |
| + switch (state) { |
| + case HDCP_STATE_UNDESIRED: |
| + value = XInternAtom(display_, "Undesired", False); |
| + break; |
| + case HDCP_STATE_DESIRED: |
| + value = XInternAtom(display_, "Desired", False); |
| + break; |
| + default: |
| + NOTREACHED() << "Invalid HDCP state: " << state; |
| + return false; |
| + } |
| + ui::X11ErrorTracker err_tracker; |
| + unsigned char *data = reinterpret_cast<unsigned char*>(&value); |
| + XRRChangeOutputProperty(display_, id, name, XA_ATOM, 32, |
| + PropModeReplace, data, 1); |
| + if (err_tracker.FoundNewError()) { |
| + LOG(ERROR) << "XRRChangeOutputProperty failed"; |
| + return false; |
| + } else { |
| + return true; |
| + } |
| +} |
| + |
| +bool RealOutputConfiguratorDelegate::QueryOutputProtectionLinkType( |
| + RROutput id, |
| + OutputType *link_type) { |
| + XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, id); |
| + if (!output_info) { |
| + return false; |
| + } |
| + |
| + bool ok = true; |
| + if (output_info->connection == RR_Connected) { |
| + std::string name(output_info->name); |
| + if (IsInternalOutput(output_info)) { |
| + *link_type = OUTPUT_TYPE_INTERNAL; |
| + } else if (name.find(kOutputName_VGA) == 0) { |
| + *link_type = OUTPUT_TYPE_VGA; |
| + } else if (name.find(kOutputName_HDMI) == 0) { |
| + *link_type = OUTPUT_TYPE_HDMI; |
| + } else if (name.find(kOutputName_DVI) == 0) { |
| + *link_type = OUTPUT_TYPE_DVI; |
| + } else if (name.find(kOutputName_DisplayPort) == 0) { |
| + *link_type = OUTPUT_TYPE_DISPLAYPORT; |
| + } else { |
| + DCHECK(0) << "Unknown link type: " << name; |
|
Daniel Erat
2013/09/20 15:00:24
use NOTREACHED() or maybe just LOG(ERROR) instead
kcwu
2013/09/20 20:29:30
Done.
|
| + ok = false; |
| + } |
| + } else { |
| + *link_type = OUTPUT_TYPE_NONE; |
| + } |
| + XRRFreeOutputInfo(output_info); |
| + return ok; |
| +} |
| + |
| +bool RealOutputConfiguratorDelegate::EnableOutputProtection( |
| + chromeos::OutputConfigurator::OutputProtectionClientId client_id, |
| + uint32_t desired_method_mask) { |
| + if (desired_method_mask == OUTPUT_PROTECTION_METHOD_NONE) |
| + client_protection_requests_.erase(client_id); |
| + else |
| + client_protection_requests_[client_id] = desired_method_mask; |
|
Daniel Erat
2013/09/20 15:00:24
should you hold off on updating the request map un
kcwu
2013/09/20 20:29:30
Done.
|
| + |
| + uint32_t all_desires = 0; |
| + for (ProtectionRequests::const_iterator it = |
| + client_protection_requests_.begin(); |
| + it != client_protection_requests_.end(); |
| + ++it) { |
| + all_desires |= it->second; |
| + } |
| + |
| + for (int i = 0; i < screen_->noutput; ++i) { |
| + RROutput this_id = screen_->outputs[i]; |
| + OutputType type; |
| + if (!QueryOutputProtectionLinkType(this_id, &type)) |
| + return false; |
| + |
| + if ((type & OUTPUT_TYPE_HDMI) || |
| + (type & OUTPUT_TYPE_DISPLAYPORT)) { |
| + HDCPState new_desired_state; |
|
Daniel Erat
2013/09/20 15:00:24
nit:
HDCPState new_desired_state =
(all_d
kcwu
2013/09/20 20:29:30
Done.
|
| + if (all_desires & OUTPUT_PROTECTION_METHOD_HDCP) { |
| + new_desired_state = HDCP_STATE_DESIRED; |
| + } else { |
| + new_desired_state = HDCP_STATE_UNDESIRED; |
| + } |
| + if (!SetHDCPState(this_id, new_desired_state)) |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +bool RealOutputConfiguratorDelegate::QueryOutputProtectionStatus( |
| + chromeos::OutputConfigurator::OutputProtectionClientId client_id, |
| + uint32_t* link_mask, |
| + uint32_t* protection_mask) { |
|
Daniel Erat
2013/09/20 15:00:24
mind adding a CHECK(screen_) here too?
but this s
Daniel Erat
2013/09/20 15:08:26
moreover, is there any reason why you can't save t
kcwu
2013/09/20 20:29:30
I'm confused. marcheu said grabbing is not strictl
kcwu
2013/09/20 20:29:30
Ah, I didn't notice OutputSnapshot was added recen
Daniel Erat
2013/09/20 20:40:59
screen_ is only valid while the server is grabbed
kcwu
2013/09/23 18:00:02
Done.
|
| + uint32_t enabled = 0; |
| + uint32_t unfulfilled = 0; |
| + |
| + *link_mask = 0; |
| + for (int i = 0; i < screen_->noutput; ++i) { |
| + RROutput this_id = screen_->outputs[i]; |
| + OutputType type; |
| + if (!QueryOutputProtectionLinkType(this_id, &type)) |
| + return false; |
| + *link_mask |= type; |
| + |
| + if ((type & OUTPUT_TYPE_HDMI) || |
| + (type & OUTPUT_TYPE_DISPLAYPORT)) { |
| + HDCPState state; |
| + RROutput this_id = screen_->outputs[i]; |
|
Daniel Erat
2013/09/20 15:00:24
i think you're shadowing the earlier |this_id| var
kcwu
2013/09/20 20:29:30
Done.
|
| + if (!GetHDCPState(this_id, &state)) |
| + return false; |
| + if (state == HDCP_STATE_ENABLED) |
| + enabled |= OUTPUT_PROTECTION_METHOD_HDCP; |
| + else |
| + unfulfilled |= OUTPUT_PROTECTION_METHOD_HDCP; |
| + } |
| + } |
| + |
| + // Don't reveal protections requested by other clients. |
| + ProtectionRequests::iterator it = client_protection_requests_.find(client_id); |
| + if (it != client_protection_requests_.end()) { |
| + uint32_t requested_mask = it->second; |
| + *protection_mask = enabled & ~unfulfilled & requested_mask; |
| + } else { |
| + *protection_mask = 0; |
| + } |
| + return true; |
| +} |
| + |
| void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( |
| const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { |
| CHECK(screen_) << "Server not grabbed"; |