| Index: ui/display/chromeos/display_configurator_unittest.cc | 
| diff --git a/ui/display/chromeos/display_configurator_unittest.cc b/ui/display/chromeos/display_configurator_unittest.cc | 
| index bd5f7e9d8cead04bf485626034edbe751b54953d..dd0eae00aee942dcc9e152ccad7c5229efcfefae 100644 | 
| --- a/ui/display/chromeos/display_configurator_unittest.cc | 
| +++ b/ui/display/chromeos/display_configurator_unittest.cc | 
| @@ -10,6 +10,7 @@ | 
| #include "ui/display/chromeos/test/action_logger_util.h" | 
| #include "ui/display/chromeos/test/test_display_snapshot.h" | 
| #include "ui/display/chromeos/test/test_native_display_delegate.h" | 
| +#include "ui/display/util/display_util.h" | 
|  | 
| namespace ui { | 
| namespace test { | 
| @@ -337,6 +338,160 @@ TEST_F(DisplayConfiguratorTest, FindDisplayModeMatchingSize) { | 
| output, gfx::Size(1440, 900))); | 
| } | 
|  | 
| +TEST_F(DisplayConfiguratorTest, EnableVirtualDisplay) { | 
| +  InitWithSingleOutput(); | 
| + | 
| +  observer_.Reset(); | 
| +  const DisplayConfigurator::DisplayStateList& cached = | 
| +      configurator_.cached_displays(); | 
| +  ASSERT_EQ(static_cast<size_t>(1u), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| + | 
| +  // Add virtual display. | 
| +  int64_t virtual_display_id = | 
| +      configurator_.AddVirtualDisplay(big_mode_.size()); | 
| +  EXPECT_EQ(GetDisplayID(0x8000, 0x0, 1), virtual_display_id); | 
| +  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | 
| +  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | 
| +            configurator_.display_state()); | 
| + | 
| +  // Virtual should not trigger addition of added crtc but does change FB | 
| +  // height. | 
| +  const int kVirtualHeight = small_mode_.size().height() + | 
| +                             DisplayConfigurator::kVerticalGap + | 
| +                             big_mode_.size().height(); | 
| +  EXPECT_EQ( | 
| +      JoinActions( | 
| +          kGrab, GetFramebufferAction( | 
| +                     gfx::Size(big_mode_.size().width(), kVirtualHeight), | 
| +                     &outputs_[0], nullptr) | 
| +                     .c_str(), | 
| +          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | 
| +          kUngrab, nullptr), | 
| +      log_->GetActionsAndClear()); | 
| +  EXPECT_EQ(1, observer_.num_changes()); | 
| +  ASSERT_EQ(static_cast<size_t>(2u), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| +  EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | 
| +  EXPECT_EQ(virtual_display_id, cached[1]->display_id()); | 
| + | 
| +  // Remove virtual display. | 
| +  observer_.Reset(); | 
| +  EXPECT_TRUE(configurator_.RemoveVirtualDisplay(virtual_display_id)); | 
| +  EXPECT_EQ( | 
| +      JoinActions( | 
| +          kGrab, GetFramebufferAction(small_mode_.size(), &outputs_[0], nullptr) | 
| +                     .c_str(), | 
| +          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | 
| +          kUngrab, nullptr), | 
| +      log_->GetActionsAndClear()); | 
| +  EXPECT_EQ(1, observer_.num_changes()); | 
| +  ASSERT_EQ(static_cast<size_t>(1u), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| +  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | 
| +} | 
| + | 
| +TEST_F(DisplayConfiguratorTest, EnableTwoVirtualDisplays) { | 
| +  InitWithSingleOutput(); | 
| + | 
| +  observer_.Reset(); | 
| +  const DisplayConfigurator::DisplayStateList& cached = | 
| +      configurator_.cached_displays(); | 
| +  ASSERT_EQ(static_cast<size_t>(1u), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| + | 
| +  // Add 1st virtual display. | 
| +  int64_t virtual_display_id_1 = | 
| +      configurator_.AddVirtualDisplay(big_mode_.size()); | 
| +  EXPECT_EQ(GetDisplayID(0x8000, 0x0, 1), virtual_display_id_1); | 
| +  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | 
| +  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | 
| +            configurator_.display_state()); | 
| + | 
| +  // Virtual should not trigger addition of added crtc but does change FB | 
| +  // height. | 
| +  const int kSingleVirtualHeight = small_mode_.size().height() + | 
| +                                   DisplayConfigurator::kVerticalGap + | 
| +                                   big_mode_.size().height(); | 
| +  EXPECT_EQ( | 
| +      JoinActions( | 
| +          kGrab, GetFramebufferAction( | 
| +                     gfx::Size(big_mode_.size().width(), kSingleVirtualHeight), | 
| +                     &outputs_[0], nullptr) | 
| +                     .c_str(), | 
| +          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | 
| +          kUngrab, nullptr), | 
| +      log_->GetActionsAndClear()); | 
| +  EXPECT_EQ(1, observer_.num_changes()); | 
| +  ASSERT_EQ(static_cast<size_t>(2), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| +  EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | 
| +  EXPECT_EQ(virtual_display_id_1, cached[1]->display_id()); | 
| + | 
| +  // Add 2nd virtual display | 
| +  int64_t virtual_display_id_2 = | 
| +      configurator_.AddVirtualDisplay(big_mode_.size()); | 
| +  EXPECT_EQ(GetDisplayID(0x8000, 0x0, 2), virtual_display_id_2); | 
| +  EXPECT_FALSE(mirroring_controller_.SoftwareMirroringEnabled()); | 
| +  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_MULTI_EXTENDED, | 
| +            configurator_.display_state()); | 
| + | 
| +  const int kDualVirtualHeight = | 
| +      small_mode_.size().height() + | 
| +      (DisplayConfigurator::kVerticalGap + big_mode_.size().height()) * 2; | 
| +  EXPECT_EQ( | 
| +      JoinActions( | 
| +          kGrab, GetFramebufferAction( | 
| +                     gfx::Size(big_mode_.size().width(), kDualVirtualHeight), | 
| +                     &outputs_[0], nullptr) | 
| +                     .c_str(), | 
| +          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | 
| +          kUngrab, nullptr), | 
| +      log_->GetActionsAndClear()); | 
| +  EXPECT_EQ(2, observer_.num_changes()); | 
| +  ASSERT_EQ(static_cast<size_t>(3u), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| +  EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | 
| +  EXPECT_EQ(big_mode_.size(), cached[2]->current_mode()->size()); | 
| +  EXPECT_EQ(virtual_display_id_1, cached[1]->display_id()); | 
| +  EXPECT_EQ(virtual_display_id_2, cached[2]->display_id()); | 
| + | 
| +  // Remove 1st virtual display. | 
| +  observer_.Reset(); | 
| +  EXPECT_TRUE(configurator_.RemoveVirtualDisplay(virtual_display_id_1)); | 
| +  EXPECT_EQ( | 
| +      JoinActions( | 
| +          kGrab, GetFramebufferAction( | 
| +                     gfx::Size(big_mode_.size().width(), kSingleVirtualHeight), | 
| +                     &outputs_[0], nullptr) | 
| +                     .c_str(), | 
| +          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | 
| +          kUngrab, nullptr), | 
| +      log_->GetActionsAndClear()); | 
| +  EXPECT_EQ(1, observer_.num_changes()); | 
| +  ASSERT_EQ(static_cast<size_t>(2u), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| +  EXPECT_EQ(big_mode_.size(), cached[1]->current_mode()->size()); | 
| +  EXPECT_EQ(virtual_display_id_2, cached[1]->display_id()); | 
| +  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_DUAL_EXTENDED, | 
| +            configurator_.display_state()); | 
| + | 
| +  // Remove 2nd virtual display. | 
| +  observer_.Reset(); | 
| +  EXPECT_TRUE(configurator_.RemoveVirtualDisplay(virtual_display_id_2)); | 
| +  EXPECT_EQ( | 
| +      JoinActions( | 
| +          kGrab, GetFramebufferAction(small_mode_.size(), &outputs_[0], nullptr) | 
| +                     .c_str(), | 
| +          GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(), | 
| +          kUngrab, nullptr), | 
| +      log_->GetActionsAndClear()); | 
| +  EXPECT_EQ(1, observer_.num_changes()); | 
| +  ASSERT_EQ(static_cast<size_t>(1), cached.size()); | 
| +  EXPECT_EQ(small_mode_.size(), cached[0]->current_mode()->size()); | 
| +  EXPECT_EQ(MULTIPLE_DISPLAY_STATE_SINGLE, configurator_.display_state()); | 
| +} | 
| + | 
| TEST_F(DisplayConfiguratorTest, ConnectSecondOutput) { | 
| InitWithSingleOutput(); | 
|  | 
| @@ -905,19 +1060,18 @@ TEST_F(DisplayConfiguratorTest, GetMultipleDisplayStateForMirroredDisplays) { | 
|  | 
| TEST_F(DisplayConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) { | 
| InitWithSingleOutput(); | 
| -  const DisplayConfigurator::DisplayStateList* cached = | 
| -      &configurator_.cached_displays(); | 
| -  ASSERT_EQ(static_cast<size_t>(1), cached->size()); | 
| -  EXPECT_EQ(outputs_[0].current_mode(), (*cached)[0]->current_mode()); | 
| +  const DisplayConfigurator::DisplayStateList& cached = | 
| +      configurator_.cached_displays(); | 
| +  ASSERT_EQ(static_cast<size_t>(1), cached.size()); | 
| +  EXPECT_EQ(outputs_[0].current_mode(), cached[0]->current_mode()); | 
|  | 
| // After connecting a second output, check that it shows up in | 
| // |cached_displays_| even if an invalid state is requested. | 
| state_controller_.set_state(MULTIPLE_DISPLAY_STATE_SINGLE); | 
| UpdateOutputs(2, true); | 
| -  cached = &configurator_.cached_displays(); | 
| -  ASSERT_EQ(static_cast<size_t>(2), cached->size()); | 
| -  EXPECT_EQ(outputs_[0].current_mode(), (*cached)[0]->current_mode()); | 
| -  EXPECT_EQ(outputs_[1].current_mode(), (*cached)[1]->current_mode()); | 
| +  ASSERT_EQ(static_cast<size_t>(2), cached.size()); | 
| +  EXPECT_EQ(outputs_[0].current_mode(), cached[0]->current_mode()); | 
| +  EXPECT_EQ(outputs_[1].current_mode(), cached[1]->current_mode()); | 
| } | 
|  | 
| TEST_F(DisplayConfiguratorTest, PanelFitting) { | 
|  |