Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chromeos/display/real_output_configurator_delegate.h" | 5 #include "chromeos/display/real_output_configurator_delegate.h" |
| 6 | 6 |
| 7 #include <X11/Xatom.h> | 7 #include <X11/Xatom.h> |
| 8 #include <X11/Xlib.h> | 8 #include <X11/Xlib.h> |
| 9 #include <X11/extensions/dpms.h> | 9 #include <X11/extensions/dpms.h> |
| 10 #include <X11/extensions/XInput.h> | 10 #include <X11/extensions/XInput.h> |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 23 | 23 |
| 24 namespace chromeos { | 24 namespace chromeos { |
| 25 | 25 |
| 26 namespace { | 26 namespace { |
| 27 | 27 |
| 28 // DPI measurements. | 28 // DPI measurements. |
| 29 const float kMmInInch = 25.4; | 29 const float kMmInInch = 25.4; |
| 30 const float kDpi96 = 96.0; | 30 const float kDpi96 = 96.0; |
| 31 const float kPixelsToMmScale = kMmInInch / kDpi96; | 31 const float kPixelsToMmScale = kMmInInch / kDpi96; |
| 32 | 32 |
| 33 // Prefixes of putput name | |
|
ddorwin
2013/09/12 04:22:13
output
kcwu
2013/09/12 18:22:08
Done.
| |
| 34 const char kOutputPortName_VGA[] = "VGA"; | |
| 35 const char kOutputPortName_HDMI[] = "HDMI"; | |
| 36 const char kOutputPortName_DVI[] = "DVI"; | |
| 37 const char kOutputPortName_DisplayPort[] = "DP"; | |
| 38 | |
| 33 bool IsInternalOutput(const XRROutputInfo* output_info) { | 39 bool IsInternalOutput(const XRROutputInfo* output_info) { |
| 34 return IsInternalOutputName(std::string(output_info->name)); | 40 return IsInternalOutputName(std::string(output_info->name)); |
| 35 } | 41 } |
| 36 | 42 |
| 37 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { | 43 RRMode GetOutputNativeMode(const XRROutputInfo* output_info) { |
| 38 return output_info->nmode > 0 ? output_info->modes[0] : None; | 44 return output_info->nmode > 0 ? output_info->modes[0] : None; |
| 39 } | 45 } |
| 40 | 46 |
| 41 } // namespace | 47 } // namespace |
| 42 | 48 |
| (...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 363 &mode_info.interlaced)) { | 369 &mode_info.interlaced)) { |
| 364 output.mode_infos.insert(std::make_pair(mode, mode_info)); | 370 output.mode_infos.insert(std::make_pair(mode, mode_info)); |
| 365 } else { | 371 } else { |
| 366 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; | 372 LOG(WARNING) << "Unable to find XRRModeInfo for mode " << mode; |
| 367 } | 373 } |
| 368 } | 374 } |
| 369 | 375 |
| 370 return output; | 376 return output; |
| 371 } | 377 } |
| 372 | 378 |
| 379 bool RealOutputConfiguratorDelegate::GetHDCPState(RROutput id, | |
| 380 HDCPState* state) { | |
| 381 CHECK(screen_) << "Server not grabbed"; | |
|
DaleCurtis
2013/09/12 01:23:13
This will crash the browser process. Do you want t
kcwu
2013/09/12 18:22:08
All checks of screen_ in this file are using CHECK
| |
| 382 unsigned char* values = NULL; | |
| 383 int actual_format = 0; | |
| 384 unsigned long nitems = 0; | |
| 385 unsigned long bytes_after = 0; | |
| 386 Atom actual_type = None; | |
| 387 int success = 0; | |
| 388 Atom prop = XInternAtom(display_, "Content Protection", False); | |
| 389 | |
| 390 bool ok = true; | |
| 391 success = XRRGetOutputProperty(display_, id, prop, 0, 100, False, | |
| 392 False, AnyPropertyType, &actual_type, | |
| 393 &actual_format, &nitems, &bytes_after, | |
| 394 &values); | |
| 395 if (actual_type == None) { | |
| 396 LOG(ERROR) << "Property 'Content Protection' does not exist"; | |
| 397 ok = false; | |
| 398 } else if (success == Success && actual_type == XA_ATOM && | |
| 399 actual_format == 32 && nitems == 1) { | |
| 400 Atom value = reinterpret_cast<Atom*>(values)[0]; | |
| 401 if (value == XInternAtom(display_, "Undesired", False)) { | |
| 402 *state = HDCP_State_Undesired; | |
| 403 } else if (value == XInternAtom(display_, "Desired", False)) { | |
| 404 *state = HDCP_State_Desired; | |
| 405 } else if (value == XInternAtom(display_, "Enabled", False)) { | |
| 406 *state = HDCP_State_Enabled; | |
| 407 } else { | |
| 408 LOG(ERROR) << "Unknown property value: " << value; | |
| 409 ok = false; | |
| 410 } | |
| 411 } else { | |
| 412 LOG(ERROR) << "XRRGetOutputProperty failed"; | |
| 413 ok = false; | |
| 414 } | |
| 415 if (values) | |
| 416 XFree(values); | |
| 417 | |
| 418 VLOG(3) << "HDCP state: " << ok << "," << *state; | |
| 419 return ok; | |
| 420 } | |
| 421 | |
| 422 bool RealOutputConfiguratorDelegate::SetHDCPState(RROutput id, | |
| 423 HDCPState state) { | |
| 424 CHECK(screen_) << "Server not grabbed"; | |
| 425 Atom name = XInternAtom(display_, "Content Protection", False); | |
| 426 Atom value; | |
| 427 switch (state) { | |
| 428 case HDCP_State_Undesired: | |
| 429 value = XInternAtom(display_, "Undesired", False); | |
| 430 break; | |
| 431 case HDCP_State_Desired: | |
| 432 value = XInternAtom(display_, "Desired", False); | |
| 433 break; | |
| 434 default: | |
| 435 DCHECK(0) << "Invalid HDCP state: " << state; | |
|
DaleCurtis
2013/09/12 01:23:13
NOTREACHED() ?
kcwu
2013/09/12 18:22:08
Done.
| |
| 436 return false; | |
| 437 } | |
| 438 unsigned char *data = reinterpret_cast<unsigned char*>(&value); | |
| 439 XRRChangeOutputProperty(display_, id, name, XA_ATOM, 32, | |
| 440 PropModeReplace, data, 1); | |
| 441 return true; | |
| 442 } | |
| 443 | |
| 444 bool DetermineLinkType(const XRROutputInfo* output_info, | |
| 445 PP_OutputProtectionLinkType_Private* link_type) { | |
| 446 std::string name(output_info->name); | |
| 447 if (IsInternalOutput(output_info)) { | |
| 448 *link_type = PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_INTERNAL; | |
| 449 } else if (name.find(kOutputPortName_VGA) == 0) { | |
| 450 *link_type = PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_VGA; | |
| 451 } else if (name.find(kOutputPortName_HDMI) == 0) { | |
| 452 *link_type = PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI; | |
| 453 } else if (name.find(kOutputPortName_DisplayPort) == 0) { | |
| 454 *link_type = PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT; | |
| 455 } else { | |
| 456 DCHECK(0) << "Unknown link type: " << name; | |
| 457 return false; | |
| 458 } | |
| 459 return true; | |
| 460 } | |
| 461 | |
| 462 bool RealOutputConfiguratorDelegate::GetOutputLinkTypes( | |
| 463 std::vector<PP_OutputProtectionLinkType_Private>* link_types) { | |
| 464 CHECK(screen_) << "Server not grabbed"; | |
| 465 bool result = true; | |
| 466 for (int i = 0; i < screen_->noutput; ++i) { | |
| 467 RROutput this_id = screen_->outputs[i]; | |
| 468 XRROutputInfo* output_info = XRRGetOutputInfo(display_, screen_, this_id); | |
|
DaleCurtis
2013/09/12 01:23:13
How expensive is this query? I ask since it'll be
kcwu
2013/09/12 18:22:08
This query should be very fast. I can measure the
| |
| 469 if (output_info == NULL) { | |
| 470 result = false; | |
| 471 break; | |
| 472 } | |
| 473 if (output_info->connection == RR_Connected) { | |
|
dmichael (off chromium)
2013/09/11 18:22:45
you could use "else if" instead of break. I find b
kcwu
2013/09/12 18:22:08
These logic are refactored into separate function,
| |
| 474 PP_OutputProtectionLinkType_Private type; | |
| 475 if (DetermineLinkType(output_info, &type)) | |
| 476 link_types->push_back(type); | |
| 477 else | |
| 478 result = false; | |
|
DaleCurtis
2013/09/12 01:23:13
Do you want to break here? Should link_types be cl
kcwu
2013/09/12 18:22:08
These logic are refactored into separate function,
| |
| 479 } else { | |
| 480 link_types->push_back(PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_NONE); | |
| 481 } | |
| 482 XRRFreeOutputInfo(output_info); | |
| 483 } | |
| 484 return result; | |
| 485 } | |
| 486 | |
| 487 bool RealOutputConfiguratorDelegate::GetOutputLinkMask( | |
|
ddorwin
2013/09/12 04:22:13
This is really a "Convert" function. Also, it coul
kcwu
2013/09/12 18:22:08
These methods are restructured.
| |
| 488 const std::vector<PP_OutputProtectionLinkType_Private>& link_types, | |
| 489 uint32_t* link_mask) { | |
| 490 *link_mask = 0; | |
| 491 | |
| 492 for (std::vector<PP_OutputProtectionLinkType_Private>::const_iterator it = | |
| 493 link_types.begin(); it != link_types.end(); ++it) { | |
| 494 *link_mask |= *it; | |
| 495 } | |
| 496 return true; | |
| 497 } | |
| 498 | |
| 499 bool RealOutputConfiguratorDelegate::GetProtectionMethods( | |
|
ddorwin
2013/09/12 04:22:13
This function could easily return the link_mask, s
kcwu
2013/09/12 18:22:08
Done.
| |
| 500 const std::vector<PP_OutputProtectionLinkType_Private>& link_types, | |
| 501 uint32_t* protection_mask) { | |
| 502 CHECK(screen_) << "Server not grabbed"; | |
| 503 uint32_t enabled = 0; | |
| 504 uint32_t unfulfiled = 0; | |
| 505 | |
| 506 DCHECK(screen_->noutput == static_cast<int>(link_types.size())); | |
|
DaleCurtis
2013/09/12 01:23:13
DCHECK_EQ ?
kcwu
2013/09/12 18:22:08
Done.
| |
| 507 for (int i = 0; i < screen_->noutput; ++i) { | |
| 508 PP_OutputProtectionLinkType_Private type = link_types[i]; | |
| 509 if ((type & PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI) || | |
| 510 (type & PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT)) { | |
| 511 HDCPState state; | |
| 512 RROutput this_id = screen_->outputs[i]; | |
| 513 if (!GetHDCPState(this_id, &state)) | |
| 514 return false; | |
| 515 if (state == HDCP_State_Enabled) | |
| 516 enabled |= PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP; | |
| 517 else | |
| 518 unfulfiled |= PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP; | |
| 519 } | |
| 520 } | |
| 521 *protection_mask = enabled & ~unfulfiled; | |
| 522 return true; | |
| 523 } | |
| 524 | |
| 525 uint32_t RealOutputConfiguratorDelegate::GetCombinedProtectionRequest() { | |
| 526 uint32_t combined_requirement = 0; | |
| 527 for (ProtectionRequests::const_iterator it = | |
| 528 client_protection_request_.begin(); | |
| 529 it != client_protection_request_.end(); | |
| 530 ++it) { | |
| 531 combined_requirement |= it->second; | |
| 532 } | |
| 533 return combined_requirement; | |
| 534 } | |
| 535 | |
| 536 bool RealOutputConfiguratorDelegate::EnableOutputProtection( | |
| 537 const chrome::PepperOutputProtectionHost* client, | |
| 538 uint32_t desired_method_mask) { | |
| 539 if (desired_method_mask == PP_OUTPUT_PROTECTION_METHOD_PRIVATE_NONE) | |
| 540 client_protection_request_.erase(client); | |
| 541 else | |
| 542 client_protection_request_[client] = desired_method_mask; | |
| 543 | |
| 544 uint32_t all_desires = GetCombinedProtectionRequest(); | |
| 545 std::vector<PP_OutputProtectionLinkType_Private> link_types; | |
| 546 if (!GetOutputLinkTypes(&link_types)) | |
|
ddorwin
2013/09/12 04:22:13
It's odd that we iterate through the outputs to ge
kcwu
2013/09/12 18:22:08
Done.
Per this suggestion. These methods are refac
| |
| 547 return false; | |
| 548 bool ok = true; | |
| 549 for (int i = 0; i < screen_->noutput; ++i) { | |
| 550 RROutput this_id = screen_->outputs[i]; | |
| 551 PP_OutputProtectionLinkType_Private type = link_types[i]; | |
| 552 if ((type & PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_HDMI) || | |
| 553 (type & PP_OUTPUT_PROTECTION_LINK_TYPE_PRIVATE_DISPLAYPORT)) { | |
| 554 if (all_desires & PP_OUTPUT_PROTECTION_METHOD_PRIVATE_HDCP) { | |
| 555 ok = SetHDCPState(this_id, HDCP_State_Desired); | |
| 556 } else { | |
| 557 ok = SetHDCPState(this_id, HDCP_State_Undesired); | |
| 558 } | |
| 559 } | |
| 560 | |
| 561 if (!ok) | |
|
ddorwin
2013/09/12 04:22:13
"&& ok" could just be a condition in the for loop
kcwu
2013/09/12 18:22:08
Done.
| |
| 562 return false; | |
| 563 } | |
| 564 return true; | |
| 565 } | |
| 566 | |
| 567 bool RealOutputConfiguratorDelegate::QueryOutputProtectionStatus( | |
| 568 const chrome::PepperOutputProtectionHost* client, | |
| 569 uint32_t* link_mask, | |
| 570 uint32_t* protection_mask) { | |
| 571 std::vector<PP_OutputProtectionLinkType_Private> link_types; | |
| 572 if (!GetOutputLinkTypes(&link_types)) | |
| 573 return false; | |
| 574 | |
| 575 bool ok = GetProtectionMethods(link_types, protection_mask) && | |
| 576 GetOutputLinkMask(link_types, link_mask); | |
| 577 ProtectionRequests::iterator it = client_protection_request_.find(client); | |
|
ddorwin
2013/09/12 04:22:13
This should be with the code below (separated by a
kcwu
2013/09/12 18:22:08
Done.
| |
| 578 | |
| 579 // Don't reveal protections requested by other clients. | |
| 580 if (it != client_protection_request_.end()) { | |
| 581 *protection_mask &= it->second; | |
|
ddorwin
2013/09/12 04:22:13
It might help to comment or assign |second| to a c
kcwu
2013/09/12 18:22:08
Done.
| |
| 582 } else { | |
| 583 *protection_mask = 0; | |
|
ddorwin
2013/09/12 04:22:13
Should this be a NOTREACHED() or can it actually h
kcwu
2013/09/12 18:22:08
This happens if the client Enable(none) and QueryS
| |
| 584 } | |
| 585 return ok; | |
| 586 } | |
| 587 | |
| 373 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( | 588 void RealOutputConfiguratorDelegate::DestroyUnusedCrtcs( |
| 374 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { | 589 const std::vector<OutputConfigurator::OutputSnapshot>& outputs) { |
| 375 CHECK(screen_) << "Server not grabbed"; | 590 CHECK(screen_) << "Server not grabbed"; |
| 376 // Setting the screen size will fail if any CRTC doesn't fit afterwards. | 591 // Setting the screen size will fail if any CRTC doesn't fit afterwards. |
| 377 // At the same time, turning CRTCs off and back on uses up a lot of time. | 592 // At the same time, turning CRTCs off and back on uses up a lot of time. |
| 378 // This function tries to be smart to avoid too many off/on cycles: | 593 // This function tries to be smart to avoid too many off/on cycles: |
| 379 // - We disable all the CRTCs we won't need after the FB resize. | 594 // - We disable all the CRTCs we won't need after the FB resize. |
| 380 // - We set the new modes on CRTCs, if they fit in both the old and new | 595 // - We set the new modes on CRTCs, if they fit in both the old and new |
| 381 // FBs, and park them at (0,0) | 596 // FBs, and park them at (0,0) |
| 382 // - We disable the CRTCs we will need but don't fit in the old FB. Those | 597 // - We disable the CRTCs we will need but don't fit in the old FB. Those |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 638 << (*outputs)[i].touch_device_id << " to output #" << i; | 853 << (*outputs)[i].touch_device_id << " to output #" << i; |
| 639 break; | 854 break; |
| 640 } | 855 } |
| 641 } | 856 } |
| 642 } | 857 } |
| 643 | 858 |
| 644 XIFreeDeviceInfo(info); | 859 XIFreeDeviceInfo(info); |
| 645 } | 860 } |
| 646 | 861 |
| 647 } // namespace chromeos | 862 } // namespace chromeos |
| OLD | NEW |