Correctly track texture cleared state for sharing
[chromium-blink-merge.git] / ui / display / chromeos / display_configurator.cc
blob97d82e5c199940a926e40c607be7b3932a0474f2
1 // Copyright 2014 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 "ui/display/chromeos/display_configurator.h"
7 #include "base/bind.h"
8 #include "base/command_line.h"
9 #include "base/logging.h"
10 #include "base/sys_info.h"
11 #include "base/time/time.h"
12 #include "ui/display/chromeos/display_util.h"
13 #include "ui/display/chromeos/update_display_configuration_task.h"
14 #include "ui/display/display_switches.h"
15 #include "ui/display/types/display_mode.h"
16 #include "ui/display/types/display_snapshot.h"
17 #include "ui/display/types/native_display_delegate.h"
19 namespace ui {
21 namespace {
23 typedef std::vector<const DisplayMode*> DisplayModeList;
25 // The delay to perform configuration after RRNotify. See the comment for
26 // |configure_timer_|.
27 const int kConfigureDelayMs = 500;
29 // The delay spent before reading the display configuration after coming out of
30 // suspend. While coming out of suspend the display state may be updating. This
31 // is used to wait until the hardware had a chance to update the display state
32 // such that we read an up to date state.
33 const int kResumeDelayMs = 500;
35 } // namespace
38 const int DisplayConfigurator::kSetDisplayPowerNoFlags = 0;
39 const int DisplayConfigurator::kSetDisplayPowerForceProbe = 1 << 0;
40 const int
41 DisplayConfigurator::kSetDisplayPowerOnlyIfSingleInternalDisplay = 1 << 1;
43 DisplayConfigurator::DisplayState::DisplayState()
44 : display(NULL),
45 selected_mode(NULL),
46 mirror_mode(NULL) {}
48 bool DisplayConfigurator::TestApi::TriggerConfigureTimeout() {
49 if (configurator_->configure_timer_.IsRunning()) {
50 configurator_->configure_timer_.user_task().Run();
51 configurator_->configure_timer_.Stop();
52 return true;
53 } else {
54 return false;
58 ////////////////////////////////////////////////////////////////////////////////
59 // DisplayConfigurator::DisplayLayoutManagerImpl implementation
61 class DisplayConfigurator::DisplayLayoutManagerImpl
62 : public DisplayLayoutManager {
63 public:
64 DisplayLayoutManagerImpl(DisplayConfigurator* configurator);
65 ~DisplayLayoutManagerImpl() override;
67 // DisplayConfigurator::DisplayLayoutManager:
68 SoftwareMirroringController* GetSoftwareMirroringController() const override;
69 StateController* GetStateController() const override;
70 MultipleDisplayState GetDisplayState() const override;
71 chromeos::DisplayPowerState GetPowerState() const override;
72 std::vector<DisplayState> ParseDisplays(
73 const std::vector<DisplaySnapshot*>& displays) const override;
74 bool GetDisplayLayout(const std::vector<DisplayState>& displays,
75 MultipleDisplayState new_display_state,
76 chromeos::DisplayPowerState new_power_state,
77 std::vector<DisplayConfigureRequest>* requests,
78 gfx::Size* framebuffer_size) const override;
80 private:
81 // Helper method for ParseDisplays() that initializes the passed-in
82 // displays' |mirror_mode| fields by looking for a mode in |internal_display|
83 // and |external_display| having the same resolution. Returns false if a
84 // shared mode wasn't found or created.
86 // |try_panel_fitting| allows creating a panel-fitting mode for
87 // |internal_display| instead of only searching for a matching mode (note that
88 // it may lead to a crash if |internal_display| is not capable of panel
89 // fitting).
91 // |preserve_aspect| limits the search/creation only to the modes having the
92 // native aspect ratio of |external_display|.
93 bool FindMirrorMode(DisplayState* internal_display,
94 DisplayState* external_display,
95 bool try_panel_fitting,
96 bool preserve_aspect) const;
98 DisplayConfigurator* configurator_; // Not owned.
100 DISALLOW_COPY_AND_ASSIGN(DisplayLayoutManagerImpl);
103 DisplayConfigurator::DisplayLayoutManagerImpl::DisplayLayoutManagerImpl(
104 DisplayConfigurator* configurator)
105 : configurator_(configurator) {
108 DisplayConfigurator::DisplayLayoutManagerImpl::~DisplayLayoutManagerImpl() {
111 DisplayConfigurator::SoftwareMirroringController*
112 DisplayConfigurator::DisplayLayoutManagerImpl::GetSoftwareMirroringController()
113 const {
114 return configurator_->mirroring_controller_;
117 DisplayConfigurator::StateController*
118 DisplayConfigurator::DisplayLayoutManagerImpl::GetStateController() const {
119 return configurator_->state_controller_;
122 MultipleDisplayState
123 DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayState() const {
124 return configurator_->current_display_state_;
127 chromeos::DisplayPowerState
128 DisplayConfigurator::DisplayLayoutManagerImpl::GetPowerState() const {
129 return configurator_->current_power_state_;
132 std::vector<DisplayConfigurator::DisplayState>
133 DisplayConfigurator::DisplayLayoutManagerImpl::ParseDisplays(
134 const std::vector<DisplaySnapshot*>& snapshots) const {
135 std::vector<DisplayState> cached_displays;
136 for (auto snapshot : snapshots) {
137 DisplayState display_state;
138 display_state.display = snapshot;
139 cached_displays.push_back(display_state);
142 // Set |selected_mode| fields.
143 for (size_t i = 0; i < cached_displays.size(); ++i) {
144 DisplayState* display_state = &cached_displays[i];
145 gfx::Size size;
146 if (GetStateController() &&
147 GetStateController()->GetResolutionForDisplayId(
148 display_state->display->display_id(), &size)) {
149 display_state->selected_mode =
150 FindDisplayModeMatchingSize(*display_state->display, size);
153 // Fall back to native mode.
154 if (!display_state->selected_mode)
155 display_state->selected_mode = display_state->display->native_mode();
158 // Set |mirror_mode| fields.
159 if (cached_displays.size() == 2) {
160 bool one_is_internal =
161 cached_displays[0].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
162 bool two_is_internal =
163 cached_displays[1].display->type() == DISPLAY_CONNECTION_TYPE_INTERNAL;
164 int internal_displays =
165 (one_is_internal ? 1 : 0) + (two_is_internal ? 1 : 0);
166 DCHECK_LT(internal_displays, 2);
167 LOG_IF(WARNING, internal_displays >= 2)
168 << "At least two internal displays detected.";
170 bool can_mirror = false;
171 for (int attempt = 0; !can_mirror && attempt < 2; ++attempt) {
172 // Try preserving external display's aspect ratio on the first attempt.
173 // If that fails, fall back to the highest matching resolution.
174 bool preserve_aspect = attempt == 0;
176 if (internal_displays == 1) {
177 can_mirror = FindMirrorMode(&cached_displays[one_is_internal ? 0 : 1],
178 &cached_displays[one_is_internal ? 1 : 0],
179 configurator_->is_panel_fitting_enabled_,
180 preserve_aspect);
181 } else { // if (internal_displays == 0)
182 // No panel fitting for external displays, so fall back to exact match.
183 can_mirror = FindMirrorMode(&cached_displays[0], &cached_displays[1],
184 false, preserve_aspect);
185 if (!can_mirror && preserve_aspect) {
186 // FindMirrorMode() will try to preserve aspect ratio of what it
187 // thinks is external display, so if it didn't succeed with one, maybe
188 // it will succeed with the other. This way we will have the correct
189 // aspect ratio on at least one of them.
190 can_mirror = FindMirrorMode(&cached_displays[1], &cached_displays[0],
191 false, preserve_aspect);
197 return cached_displays;
200 bool DisplayConfigurator::DisplayLayoutManagerImpl::GetDisplayLayout(
201 const std::vector<DisplayState>& displays,
202 MultipleDisplayState new_display_state,
203 chromeos::DisplayPowerState new_power_state,
204 std::vector<DisplayConfigureRequest>* requests,
205 gfx::Size* framebuffer_size) const {
206 std::vector<bool> display_power;
207 int num_on_displays =
208 GetDisplayPower(displays, new_power_state, &display_power);
209 VLOG(1) << "EnterState: display="
210 << MultipleDisplayStateToString(new_display_state)
211 << " power=" << DisplayPowerStateToString(new_power_state);
213 // Framebuffer dimensions.
214 gfx::Size size;
216 for (size_t i = 0; i < displays.size(); ++i) {
217 requests->push_back(DisplayConfigureRequest(
218 displays[i].display, displays[i].display->current_mode(),
219 gfx::Point()));
222 switch (new_display_state) {
223 case MULTIPLE_DISPLAY_STATE_INVALID:
224 NOTREACHED() << "Ignoring request to enter invalid state with "
225 << displays.size() << " connected display(s)";
226 return false;
227 case MULTIPLE_DISPLAY_STATE_HEADLESS:
228 if (displays.size() != 0) {
229 LOG(WARNING) << "Ignoring request to enter headless mode with "
230 << displays.size() << " connected display(s)";
231 return false;
233 break;
234 case MULTIPLE_DISPLAY_STATE_SINGLE: {
235 // If there are multiple displays connected, only one should be turned on.
236 if (displays.size() != 1 && num_on_displays != 1) {
237 LOG(WARNING) << "Ignoring request to enter single mode with "
238 << displays.size() << " connected displays and "
239 << num_on_displays << " turned on";
240 return false;
243 for (size_t i = 0; i < displays.size(); ++i) {
244 const DisplayConfigurator::DisplayState* state = &displays[i];
245 (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL;
247 if (display_power[i] || displays.size() == 1) {
248 const DisplayMode* mode_info = state->selected_mode;
249 if (!mode_info) {
250 LOG(WARNING) << "No selected mode when configuring display: "
251 << state->display->ToString();
252 return false;
254 if (mode_info->size() == gfx::Size(1024, 768)) {
255 VLOG(1) << "Potentially misdetecting display(1024x768):"
256 << " displays size=" << displays.size()
257 << ", num_on_displays=" << num_on_displays
258 << ", current size:" << size.width() << "x" << size.height()
259 << ", i=" << i << ", display=" << state->display->ToString()
260 << ", display_mode=" << mode_info->ToString();
262 size = mode_info->size();
265 break;
267 case MULTIPLE_DISPLAY_STATE_DUAL_MIRROR: {
268 if (displays.size() != 2 ||
269 (num_on_displays != 0 && num_on_displays != 2)) {
270 LOG(WARNING) << "Ignoring request to enter mirrored mode with "
271 << displays.size() << " connected display(s) and "
272 << num_on_displays << " turned on";
273 return false;
276 const DisplayMode* mode_info = displays[0].mirror_mode;
277 if (!mode_info) {
278 LOG(WARNING) << "No mirror mode when configuring display: "
279 << displays[0].display->ToString();
280 return false;
282 size = mode_info->size();
284 for (size_t i = 0; i < displays.size(); ++i) {
285 const DisplayConfigurator::DisplayState* state = &displays[i];
286 (*requests)[i].mode = display_power[i] ? state->mirror_mode : NULL;
288 break;
290 case MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED:
291 case MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED: {
292 if ((new_display_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED &&
293 displays.size() != 2) ||
294 (new_display_state == MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED &&
295 displays.size() <= 2) ||
296 (num_on_displays != 0 &&
297 num_on_displays != static_cast<int>(displays.size()))) {
298 LOG(WARNING) << "Ignoring request to enter extended mode with "
299 << displays.size() << " connected display(s) and "
300 << num_on_displays << " turned on";
301 return false;
304 for (size_t i = 0; i < displays.size(); ++i) {
305 const DisplayConfigurator::DisplayState* state = &displays[i];
306 (*requests)[i].origin.set_y(size.height() ? size.height() + kVerticalGap
307 : 0);
308 (*requests)[i].mode = display_power[i] ? state->selected_mode : NULL;
310 // Retain the full screen size even if all displays are off so the
311 // same desktop configuration can be restored when the displays are
312 // turned back on.
313 const DisplayMode* mode_info = displays[i].selected_mode;
314 if (!mode_info) {
315 LOG(WARNING) << "No selected mode when configuring display: "
316 << state->display->ToString();
317 return false;
320 size.set_width(std::max<int>(size.width(), mode_info->size().width()));
321 size.set_height(size.height() + (size.height() ? kVerticalGap : 0) +
322 mode_info->size().height());
324 break;
328 *framebuffer_size = size;
329 return true;
332 bool DisplayConfigurator::DisplayLayoutManagerImpl::FindMirrorMode(
333 DisplayState* internal_display,
334 DisplayState* external_display,
335 bool try_panel_fitting,
336 bool preserve_aspect) const {
337 const DisplayMode* internal_native_info =
338 internal_display->display->native_mode();
339 const DisplayMode* external_native_info =
340 external_display->display->native_mode();
341 if (!internal_native_info || !external_native_info)
342 return false;
344 // Check if some external display resolution can be mirrored on internal.
345 // Prefer the modes in the order they're present in DisplaySnapshot, assuming
346 // this is the order in which they look better on the monitor.
347 for (DisplayModeList::const_iterator external_it =
348 external_display->display->modes().begin();
349 external_it != external_display->display->modes().end(); ++external_it) {
350 const DisplayMode& external_info = **external_it;
351 bool is_native_aspect_ratio =
352 external_native_info->size().width() * external_info.size().height() ==
353 external_native_info->size().height() * external_info.size().width();
354 if (preserve_aspect && !is_native_aspect_ratio)
355 continue; // Allow only aspect ratio preserving modes for mirroring.
357 // Try finding an exact match.
358 for (DisplayModeList::const_iterator internal_it =
359 internal_display->display->modes().begin();
360 internal_it != internal_display->display->modes().end();
361 ++internal_it) {
362 const DisplayMode& internal_info = **internal_it;
363 if (internal_info.size().width() == external_info.size().width() &&
364 internal_info.size().height() == external_info.size().height() &&
365 internal_info.is_interlaced() == external_info.is_interlaced()) {
366 internal_display->mirror_mode = *internal_it;
367 external_display->mirror_mode = *external_it;
368 return true; // Mirror mode found.
372 // Try to create a matching internal display mode by panel fitting.
373 if (try_panel_fitting) {
374 // We can downscale by 1.125, and upscale indefinitely. Downscaling looks
375 // ugly, so, can fit == can upscale. Also, internal panels don't support
376 // fitting interlaced modes.
377 bool can_fit = internal_native_info->size().width() >=
378 external_info.size().width() &&
379 internal_native_info->size().height() >=
380 external_info.size().height() &&
381 !external_info.is_interlaced();
382 if (can_fit) {
383 configurator_->native_display_delegate_->AddMode(
384 *internal_display->display, *external_it);
385 internal_display->display->add_mode(*external_it);
386 internal_display->mirror_mode = *external_it;
387 external_display->mirror_mode = *external_it;
388 return true; // Mirror mode created.
393 return false;
396 ////////////////////////////////////////////////////////////////////////////////
397 // DisplayConfigurator implementation
399 // static
400 const DisplayMode* DisplayConfigurator::FindDisplayModeMatchingSize(
401 const DisplaySnapshot& display,
402 const gfx::Size& size) {
403 const DisplayMode* best_mode = NULL;
404 for (DisplayModeList::const_iterator it = display.modes().begin();
405 it != display.modes().end();
406 ++it) {
407 const DisplayMode* mode = *it;
409 if (mode->size() != size)
410 continue;
412 if (mode == display.native_mode()) {
413 best_mode = mode;
414 break;
417 if (!best_mode) {
418 best_mode = mode;
419 continue;
422 if (mode->is_interlaced()) {
423 if (!best_mode->is_interlaced())
424 continue;
425 } else {
426 // Reset the best rate if the non interlaced is
427 // found the first time.
428 if (best_mode->is_interlaced()) {
429 best_mode = mode;
430 continue;
433 if (mode->refresh_rate() < best_mode->refresh_rate())
434 continue;
436 best_mode = mode;
439 return best_mode;
442 DisplayConfigurator::DisplayConfigurator()
443 : state_controller_(NULL),
444 mirroring_controller_(NULL),
445 is_panel_fitting_enabled_(false),
446 configure_display_(base::SysInfo::IsRunningOnChromeOS()),
447 current_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
448 current_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
449 requested_display_state_(MULTIPLE_DISPLAY_STATE_INVALID),
450 requested_power_state_(chromeos::DISPLAY_POWER_ALL_ON),
451 requested_power_state_change_(false),
452 requested_power_flags_(kSetDisplayPowerNoFlags),
453 force_configure_(false),
454 next_display_protection_client_id_(1),
455 display_externally_controlled_(false),
456 layout_manager_(new DisplayLayoutManagerImpl(this)),
457 weak_ptr_factory_(this) {
460 DisplayConfigurator::~DisplayConfigurator() {
461 if (native_display_delegate_)
462 native_display_delegate_->RemoveObserver(this);
465 void DisplayConfigurator::SetDelegateForTesting(
466 scoped_ptr<NativeDisplayDelegate> display_delegate) {
467 DCHECK(!native_display_delegate_);
469 native_display_delegate_ = display_delegate.Pass();
470 configure_display_ = true;
473 void DisplayConfigurator::SetInitialDisplayPower(
474 chromeos::DisplayPowerState power_state) {
475 DCHECK_EQ(current_display_state_, MULTIPLE_DISPLAY_STATE_INVALID);
476 requested_power_state_ = current_power_state_ = power_state;
479 void DisplayConfigurator::Init(bool is_panel_fitting_enabled) {
480 is_panel_fitting_enabled_ = is_panel_fitting_enabled;
481 if (!configure_display_ || display_externally_controlled_)
482 return;
484 // If the delegate is already initialized don't update it (For example, tests
485 // set their own delegates).
486 if (!native_display_delegate_) {
487 native_display_delegate_ = CreatePlatformNativeDisplayDelegate();
488 native_display_delegate_->AddObserver(this);
492 void DisplayConfigurator::TakeControl() {
493 if (cached_displays_.empty())
494 return;
496 if (!display_externally_controlled_)
497 return;
499 if (!native_display_delegate_->TakeDisplayControl())
500 return;
502 display_externally_controlled_ = false;
503 force_configure_ = true;
504 RunPendingConfiguration();
507 void DisplayConfigurator::RelinquishControl() {
508 if (display_externally_controlled_)
509 return;
511 display_externally_controlled_ = true;
512 native_display_delegate_->RelinquishDisplayControl();
515 void DisplayConfigurator::ForceInitialConfigure(
516 uint32_t background_color_argb) {
517 if (!configure_display_ || display_externally_controlled_)
518 return;
520 native_display_delegate_->Initialize();
522 // ForceInitialConfigure should be the first configuration so there shouldn't
523 // be anything scheduled.
524 DCHECK(!configuration_task_);
526 configuration_task_.reset(new UpdateDisplayConfigurationTask(
527 native_display_delegate_.get(), layout_manager_.get(),
528 requested_display_state_, requested_power_state_,
529 kSetDisplayPowerForceProbe, background_color_argb, true,
530 base::Bind(&DisplayConfigurator::OnConfigured,
531 weak_ptr_factory_.GetWeakPtr())));
532 configuration_task_->Run();
535 bool DisplayConfigurator::IsMirroring() const {
536 return current_display_state_ == MULTIPLE_DISPLAY_STATE_DUAL_MIRROR ||
537 (mirroring_controller_ &&
538 mirroring_controller_->SoftwareMirroringEnabled());
541 bool DisplayConfigurator::ApplyProtections(const ContentProtections& requests) {
542 for (DisplayStateList::const_iterator it = cached_displays_.begin();
543 it != cached_displays_.end();
544 ++it) {
545 uint32_t all_desired = 0;
547 // In mirror mode, protection request of all displays need to be fulfilled.
548 // In non-mirror mode, only request of client's display needs to be
549 // fulfilled.
550 ContentProtections::const_iterator request_it;
551 if (IsMirroring()) {
552 for (request_it = requests.begin();
553 request_it != requests.end();
554 ++request_it)
555 all_desired |= request_it->second;
556 } else {
557 request_it = requests.find(it->display->display_id());
558 if (request_it != requests.end())
559 all_desired = request_it->second;
562 switch (it->display->type()) {
563 case DISPLAY_CONNECTION_TYPE_UNKNOWN:
564 return false;
565 // DisplayPort, DVI, and HDMI all support HDCP.
566 case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
567 case DISPLAY_CONNECTION_TYPE_DVI:
568 case DISPLAY_CONNECTION_TYPE_HDMI: {
569 HDCPState current_state;
570 // Need to poll the driver for updates since other applications may
571 // have updated the state.
572 if (!native_display_delegate_->GetHDCPState(*it->display,
573 &current_state))
574 return false;
575 bool current_desired = (current_state != HDCP_STATE_UNDESIRED);
576 bool new_desired = (all_desired & CONTENT_PROTECTION_METHOD_HDCP);
577 // Don't enable again if HDCP is already active. Some buggy drivers
578 // may disable and enable if setting "desired" in active state.
579 if (current_desired != new_desired) {
580 HDCPState new_state =
581 new_desired ? HDCP_STATE_DESIRED : HDCP_STATE_UNDESIRED;
582 if (!native_display_delegate_->SetHDCPState(*it->display, new_state))
583 return false;
585 break;
587 case DISPLAY_CONNECTION_TYPE_INTERNAL:
588 case DISPLAY_CONNECTION_TYPE_VGA:
589 case DISPLAY_CONNECTION_TYPE_NETWORK:
590 // No protections for these types. Do nothing.
591 break;
592 case DISPLAY_CONNECTION_TYPE_NONE:
593 NOTREACHED();
594 break;
598 return true;
601 DisplayConfigurator::ContentProtectionClientId
602 DisplayConfigurator::RegisterContentProtectionClient() {
603 if (!configure_display_ || display_externally_controlled_)
604 return kInvalidClientId;
606 return next_display_protection_client_id_++;
609 void DisplayConfigurator::UnregisterContentProtectionClient(
610 ContentProtectionClientId client_id) {
611 client_protection_requests_.erase(client_id);
613 ContentProtections protections;
614 for (ProtectionRequests::const_iterator it =
615 client_protection_requests_.begin();
616 it != client_protection_requests_.end();
617 ++it) {
618 for (ContentProtections::const_iterator it2 = it->second.begin();
619 it2 != it->second.end();
620 ++it2) {
621 protections[it2->first] |= it2->second;
625 ApplyProtections(protections);
628 bool DisplayConfigurator::QueryContentProtectionStatus(
629 ContentProtectionClientId client_id,
630 int64_t display_id,
631 uint32_t* link_mask,
632 uint32_t* protection_mask) {
633 if (!configure_display_ || display_externally_controlled_)
634 return false;
636 uint32_t enabled = 0;
637 uint32_t unfulfilled = 0;
638 *link_mask = 0;
639 for (DisplayStateList::const_iterator it = cached_displays_.begin();
640 it != cached_displays_.end();
641 ++it) {
642 // Query display if it is in mirror mode or client on the same display.
643 if (!IsMirroring() && it->display->display_id() != display_id)
644 continue;
646 *link_mask |= it->display->type();
647 switch (it->display->type()) {
648 case DISPLAY_CONNECTION_TYPE_UNKNOWN:
649 return false;
650 // DisplayPort, DVI, and HDMI all support HDCP.
651 case DISPLAY_CONNECTION_TYPE_DISPLAYPORT:
652 case DISPLAY_CONNECTION_TYPE_DVI:
653 case DISPLAY_CONNECTION_TYPE_HDMI: {
654 HDCPState state;
655 if (!native_display_delegate_->GetHDCPState(*it->display, &state))
656 return false;
657 if (state == HDCP_STATE_ENABLED)
658 enabled |= CONTENT_PROTECTION_METHOD_HDCP;
659 else
660 unfulfilled |= CONTENT_PROTECTION_METHOD_HDCP;
661 break;
663 case DISPLAY_CONNECTION_TYPE_INTERNAL:
664 case DISPLAY_CONNECTION_TYPE_VGA:
665 case DISPLAY_CONNECTION_TYPE_NETWORK:
666 // No protections for these types. Do nothing.
667 break;
668 case DISPLAY_CONNECTION_TYPE_NONE:
669 NOTREACHED();
670 break;
674 // Don't reveal protections requested by other clients.
675 ProtectionRequests::iterator it = client_protection_requests_.find(client_id);
676 if (it != client_protection_requests_.end()) {
677 uint32_t requested_mask = 0;
678 if (it->second.find(display_id) != it->second.end())
679 requested_mask = it->second[display_id];
680 *protection_mask = enabled & ~unfulfilled & requested_mask;
681 } else {
682 *protection_mask = 0;
684 return true;
687 bool DisplayConfigurator::EnableContentProtection(
688 ContentProtectionClientId client_id,
689 int64_t display_id,
690 uint32_t desired_method_mask) {
691 if (!configure_display_ || display_externally_controlled_)
692 return false;
694 ContentProtections protections;
695 for (ProtectionRequests::const_iterator it =
696 client_protection_requests_.begin();
697 it != client_protection_requests_.end();
698 ++it) {
699 for (ContentProtections::const_iterator it2 = it->second.begin();
700 it2 != it->second.end();
701 ++it2) {
702 if (it->first == client_id && it2->first == display_id)
703 continue;
704 protections[it2->first] |= it2->second;
707 protections[display_id] |= desired_method_mask;
709 if (!ApplyProtections(protections))
710 return false;
712 if (desired_method_mask == CONTENT_PROTECTION_METHOD_NONE) {
713 if (client_protection_requests_.find(client_id) !=
714 client_protection_requests_.end()) {
715 client_protection_requests_[client_id].erase(display_id);
716 if (client_protection_requests_[client_id].size() == 0)
717 client_protection_requests_.erase(client_id);
719 } else {
720 client_protection_requests_[client_id][display_id] = desired_method_mask;
723 return true;
726 std::vector<ui::ColorCalibrationProfile>
727 DisplayConfigurator::GetAvailableColorCalibrationProfiles(int64_t display_id) {
728 if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
729 switches::kDisableDisplayColorCalibration)) {
730 for (size_t i = 0; i < cached_displays_.size(); ++i) {
731 if (cached_displays_[i].display &&
732 cached_displays_[i].display->display_id() == display_id) {
733 return native_display_delegate_->GetAvailableColorCalibrationProfiles(
734 *cached_displays_[i].display);
739 return std::vector<ui::ColorCalibrationProfile>();
742 bool DisplayConfigurator::SetColorCalibrationProfile(
743 int64_t display_id,
744 ui::ColorCalibrationProfile new_profile) {
745 for (size_t i = 0; i < cached_displays_.size(); ++i) {
746 if (cached_displays_[i].display &&
747 cached_displays_[i].display->display_id() == display_id) {
748 return native_display_delegate_->SetColorCalibrationProfile(
749 *cached_displays_[i].display, new_profile);
753 return false;
756 void DisplayConfigurator::PrepareForExit() {
757 configure_display_ = false;
760 void DisplayConfigurator::SetDisplayPower(
761 chromeos::DisplayPowerState power_state,
762 int flags) {
763 if (!configure_display_ || display_externally_controlled_)
764 return;
766 VLOG(1) << "SetDisplayPower: power_state="
767 << DisplayPowerStateToString(power_state) << " flags=" << flags
768 << ", configure timer="
769 << (configure_timer_.IsRunning() ? "Running" : "Stopped");
770 if (power_state == requested_power_state_ &&
771 !(flags & kSetDisplayPowerForceProbe))
772 return;
774 requested_power_state_ = power_state;
775 requested_power_state_change_ = true;
776 requested_power_flags_ = flags;
778 RunPendingConfiguration();
781 void DisplayConfigurator::SetDisplayMode(MultipleDisplayState new_state) {
782 if (!configure_display_ || display_externally_controlled_)
783 return;
785 VLOG(1) << "SetDisplayMode: state="
786 << MultipleDisplayStateToString(new_state);
787 if (current_display_state_ == new_state) {
788 // Cancel software mirroring if the state is moving from
789 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED to
790 // MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED.
791 if (mirroring_controller_ &&
792 new_state == MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED)
793 mirroring_controller_->SetSoftwareMirroring(false);
794 NotifyObservers(true, new_state);
795 return;
798 requested_display_state_ = new_state;
800 RunPendingConfiguration();
803 void DisplayConfigurator::OnConfigurationChanged() {
804 // Configure displays with |kConfigureDelayMs| delay,
805 // so that time-consuming ConfigureDisplays() won't be called multiple times.
806 if (configure_timer_.IsRunning()) {
807 // Note: when the timer is running it is possible that a different task
808 // (RestoreRequestedPowerStateAfterResume()) is scheduled. In these cases,
809 // prefer the already scheduled task to ConfigureDisplays() since
810 // ConfigureDisplays() performs only basic configuration while
811 // RestoreRequestedPowerStateAfterResume() will perform additional
812 // operations.
813 configure_timer_.Reset();
814 } else {
815 configure_timer_.Start(
816 FROM_HERE,
817 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
818 this,
819 &DisplayConfigurator::ConfigureDisplays);
823 void DisplayConfigurator::AddObserver(Observer* observer) {
824 observers_.AddObserver(observer);
827 void DisplayConfigurator::RemoveObserver(Observer* observer) {
828 observers_.RemoveObserver(observer);
831 void DisplayConfigurator::SuspendDisplays() {
832 // If the display is off due to user inactivity and there's only a single
833 // internal display connected, switch to the all-on state before
834 // suspending. This shouldn't be very noticeable to the user since the
835 // backlight is off at this point, and doing this lets us resume directly
836 // into the "on" state, which greatly reduces resume times.
837 if (requested_power_state_ == chromeos::DISPLAY_POWER_ALL_OFF) {
838 SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
839 kSetDisplayPowerOnlyIfSingleInternalDisplay);
841 // We need to make sure that the monitor configuration we just did actually
842 // completes before we return, because otherwise the X message could be
843 // racing with the HandleSuspendReadiness message.
844 native_display_delegate_->SyncWithServer();
848 void DisplayConfigurator::ResumeDisplays() {
849 configure_timer_.Start(
850 FROM_HERE,
851 base::TimeDelta::FromMilliseconds(kResumeDelayMs),
852 base::Bind(&DisplayConfigurator::RestoreRequestedPowerStateAfterResume,
853 base::Unretained(this)));
856 void DisplayConfigurator::ConfigureDisplays() {
857 if (!configure_display_ || display_externally_controlled_)
858 return;
860 force_configure_ = true;
861 RunPendingConfiguration();
864 void DisplayConfigurator::RunPendingConfiguration() {
865 // Configuration task is currently running. Do not start a second
866 // configuration.
867 if (configuration_task_)
868 return;
870 if (!ShouldRunConfigurationTask()) {
871 LOG(ERROR) << "Called RunPendingConfiguration without any changes"
872 " requested";
873 return;
876 configuration_task_.reset(new UpdateDisplayConfigurationTask(
877 native_display_delegate_.get(), layout_manager_.get(),
878 requested_display_state_, requested_power_state_, requested_power_flags_,
879 0, force_configure_, base::Bind(&DisplayConfigurator::OnConfigured,
880 weak_ptr_factory_.GetWeakPtr())));
882 // Reset the flags before running the task; otherwise it may end up scheduling
883 // another configuration.
884 force_configure_ = false;
885 requested_power_flags_ = kSetDisplayPowerNoFlags;
886 requested_power_state_change_ = false;
887 requested_display_state_ = MULTIPLE_DISPLAY_STATE_INVALID;
889 configuration_task_->Run();
892 void DisplayConfigurator::OnConfigured(
893 bool success,
894 const std::vector<DisplayState>& displays,
895 const gfx::Size& framebuffer_size,
896 MultipleDisplayState new_display_state,
897 chromeos::DisplayPowerState new_power_state) {
898 VLOG(1) << "OnConfigured: success=" << success << " new_display_state="
899 << MultipleDisplayStateToString(new_display_state)
900 << " new_power_state=" << DisplayPowerStateToString(new_power_state);
902 cached_displays_ = displays;
903 if (success) {
904 current_display_state_ = new_display_state;
905 current_power_state_ = new_power_state;
906 framebuffer_size_ = framebuffer_size;
907 // If the requested power state hasn't changed then make sure that value
908 // gets updated as well since the last requested value may have been
909 // dependent on certain conditions (ie: if only the internal monitor was
910 // present).
911 if (!requested_power_state_change_)
912 requested_power_state_ = new_power_state;
915 configuration_task_.reset();
916 NotifyObservers(success, new_display_state);
918 if (success && !configure_timer_.IsRunning() &&
919 ShouldRunConfigurationTask()) {
920 configure_timer_.Start(FROM_HERE,
921 base::TimeDelta::FromMilliseconds(kConfigureDelayMs),
922 this, &DisplayConfigurator::RunPendingConfiguration);
926 bool DisplayConfigurator::ShouldRunConfigurationTask() const {
927 if (force_configure_)
928 return true;
930 // Schedule if there is a request to change the display state.
931 if (requested_display_state_ != current_display_state_ &&
932 requested_display_state_ != MULTIPLE_DISPLAY_STATE_INVALID)
933 return true;
935 // Schedule if there is a request to change the power state.
936 if (requested_power_state_change_)
937 return true;
939 return false;
942 void DisplayConfigurator::RestoreRequestedPowerStateAfterResume() {
943 // Force probing to ensure that we pick up any changes that were made while
944 // the system was suspended.
945 SetDisplayPower(requested_power_state_, kSetDisplayPowerForceProbe);
948 void DisplayConfigurator::NotifyObservers(
949 bool success,
950 MultipleDisplayState attempted_state) {
951 if (success) {
952 FOR_EACH_OBSERVER(
953 Observer, observers_, OnDisplayModeChanged(cached_displays_));
954 } else {
955 FOR_EACH_OBSERVER(
956 Observer, observers_, OnDisplayModeChangeFailed(attempted_state));
960 } // namespace ui