Home | History | Annotate | Download | only in display
      1 // Copyright (c) 2012 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 "chromeos/display/output_configurator.h"
      6 
      7 #include <cmath>
      8 #include <cstdarg>
      9 #include <map>
     10 #include <string>
     11 #include <vector>
     12 
     13 #include "base/basictypes.h"
     14 #include "base/compiler_specific.h"
     15 #include "base/message_loop/message_loop.h"
     16 #include "base/strings/stringprintf.h"
     17 #include "testing/gtest/include/gtest/gtest.h"
     18 
     19 namespace chromeos {
     20 
     21 namespace {
     22 
     23 // Strings returned by TestDelegate::GetActionsAndClear() to describe various
     24 // actions that were performed.
     25 const char kInitXRandR[] = "init";
     26 const char kUpdateXRandR[] = "update";
     27 const char kGrab[] = "grab";
     28 const char kUngrab[] = "ungrab";
     29 const char kSync[] = "sync";
     30 const char kForceDPMS[] = "dpms";
     31 const char kProjectingOn[] = "projecting";
     32 const char kProjectingOff[] = "not_projecting";
     33 
     34 // String returned by TestDelegate::GetActionsAndClear() if no actions were
     35 // requested.
     36 const char kNoActions[] = "";
     37 
     38 // Returns a string describing a TestDelegate::SetBackgroundColor() call.
     39 std::string GetBackgroundAction(uint32 color_argb) {
     40   return base::StringPrintf("background(0x%x)", color_argb);
     41 }
     42 
     43 // Returns a string describing a TestDelegate::AddOutputMode() call.
     44 std::string GetAddOutputModeAction(RROutput output, RRMode mode) {
     45   return base::StringPrintf("add_mode(output=%lu,mode=%lu)", output, mode);
     46 }
     47 
     48 // Returns a string describing a TestDelegate::ConfigureCrtc() call.
     49 std::string GetCrtcAction(RRCrtc crtc,
     50                           int x,
     51                           int y,
     52                           RRMode mode,
     53                           RROutput output) {
     54   return base::StringPrintf("crtc(crtc=%lu,x=%d,y=%d,mode=%lu,output=%lu)",
     55                             crtc, x, y, mode, output);
     56 }
     57 
     58 // Returns a string describing a TestDelegate::CreateFramebuffer() call.
     59 std::string GetFramebufferAction(int width,
     60                                  int height,
     61                                  RRCrtc crtc1,
     62                                  RRCrtc crtc2) {
     63   return base::StringPrintf(
     64       "framebuffer(width=%d,height=%d,crtc1=%lu,crtc2=%lu)",
     65       width, height, crtc1, crtc2);
     66 }
     67 
     68 // Returns a string describing a TestDelegate::ConfigureCTM() call.
     69 std::string GetCTMAction(
     70     int device_id,
     71     const OutputConfigurator::CoordinateTransformation& ctm) {
     72   return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))", device_id,
     73       ctm.x_scale, ctm.x_offset, ctm.y_scale, ctm.y_offset);
     74 }
     75 
     76 // Returns a string describing a TestDelegate::SetHDCPState() call.
     77 std::string GetSetHDCPStateAction(RROutput id, HDCPState state) {
     78   return base::StringPrintf("set_hdcp(id=%lu,state=%d)", id, state);
     79 }
     80 
     81 // Joins a sequence of strings describing actions (e.g. kScreenDim) such
     82 // that they can be compared against a string returned by
     83 // TestDelegate::GetActionsAndClear().  The list of actions must be
     84 // terminated by a NULL pointer.
     85 std::string JoinActions(const char* action, ...) {
     86   std::string actions;
     87 
     88   va_list arg_list;
     89   va_start(arg_list, action);
     90   while (action) {
     91     if (!actions.empty())
     92       actions += ",";
     93     actions += action;
     94     action = va_arg(arg_list, const char*);
     95   }
     96   va_end(arg_list);
     97   return actions;
     98 }
     99 
    100 class TestDelegate : public OutputConfigurator::Delegate {
    101  public:
    102   static const int kXRandREventBase = 10;
    103 
    104   TestDelegate()
    105       : configure_crtc_result_(true),
    106         hdcp_state_(HDCP_STATE_UNDESIRED) {}
    107   virtual ~TestDelegate() {}
    108 
    109   const std::vector<OutputConfigurator::OutputSnapshot>& outputs() const {
    110     return outputs_;
    111   }
    112   void set_outputs(
    113       const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
    114     outputs_ = outputs;
    115   }
    116 
    117   void set_configure_crtc_result(bool result) {
    118     configure_crtc_result_ = result;
    119   }
    120 
    121   void set_hdcp_state(HDCPState state) { hdcp_state_ = state; }
    122 
    123   // Returns a comma-separated string describing the actions that were
    124   // requested since the previous call to GetActionsAndClear() (i.e.
    125   // results are non-repeatable).
    126   std::string GetActionsAndClear() {
    127     std::string actions = actions_;
    128     actions_.clear();
    129     return actions;
    130   }
    131 
    132   const OutputConfigurator::CoordinateTransformation& get_ctm(
    133       int touch_device_id) {
    134     return ctms_[touch_device_id];
    135   }
    136 
    137   // OutputConfigurator::Delegate overrides:
    138   virtual void InitXRandRExtension(int* event_base) OVERRIDE {
    139     AppendAction(kInitXRandR);
    140     *event_base = kXRandREventBase;
    141   }
    142   virtual void UpdateXRandRConfiguration(
    143       const base::NativeEvent& event) OVERRIDE { AppendAction(kUpdateXRandR); }
    144   virtual void GrabServer() OVERRIDE { AppendAction(kGrab); }
    145   virtual void UngrabServer() OVERRIDE { AppendAction(kUngrab); }
    146   virtual void SyncWithServer() OVERRIDE { AppendAction(kSync); }
    147   virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE {
    148     AppendAction(GetBackgroundAction(color_argb));
    149   }
    150   virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); }
    151   virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs()
    152       OVERRIDE {
    153     return outputs_;
    154   }
    155   virtual void AddOutputMode(RROutput output, RRMode mode) OVERRIDE {
    156     AppendAction(GetAddOutputModeAction(output, mode));
    157   }
    158   virtual bool ConfigureCrtc(RRCrtc crtc,
    159                              RRMode mode,
    160                              RROutput output,
    161                              int x,
    162                              int y) OVERRIDE {
    163     AppendAction(GetCrtcAction(crtc, x, y, mode, output));
    164     return configure_crtc_result_;
    165   }
    166   virtual void CreateFrameBuffer(
    167       int width,
    168       int height,
    169       const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
    170     AppendAction(
    171         GetFramebufferAction(width,
    172                              height,
    173                              outputs.size() >= 1 ? outputs[0].crtc : 0,
    174                              outputs.size() >= 2 ? outputs[1].crtc : 0));
    175   }
    176   virtual void ConfigureCTM(
    177       int touch_device_id,
    178       const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
    179     AppendAction(GetCTMAction(touch_device_id, ctm));
    180     ctms_[touch_device_id] = ctm;
    181   }
    182   virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
    183     AppendAction(projecting ? kProjectingOn : kProjectingOff);
    184   }
    185 
    186   virtual bool GetHDCPState(RROutput id, HDCPState* state) OVERRIDE {
    187     *state = hdcp_state_;
    188     return true;
    189   }
    190 
    191   virtual bool SetHDCPState(RROutput id, HDCPState state) OVERRIDE {
    192     AppendAction(GetSetHDCPStateAction(id, state));
    193     return true;
    194   }
    195 
    196  private:
    197   struct ModeDetails {
    198     ModeDetails() : width(0), height(0), interlaced(false) {}
    199     ModeDetails(int width, int height, bool interlaced)
    200         : width(width),
    201           height(height),
    202           interlaced(interlaced) {}
    203 
    204     int width;
    205     int height;
    206     bool interlaced;
    207   };
    208 
    209   void AppendAction(const std::string& action) {
    210     if (!actions_.empty())
    211       actions_ += ",";
    212     actions_ += action;
    213   }
    214 
    215   std::map<RRMode, ModeDetails> modes_;
    216 
    217   // Most-recently-configured transformation matrices, keyed by touch device ID.
    218   std::map<int, OutputConfigurator::CoordinateTransformation> ctms_;
    219 
    220   // Outputs to be returned by GetOutputs().
    221   std::vector<OutputConfigurator::OutputSnapshot> outputs_;
    222 
    223   std::string actions_;
    224 
    225   // Return value returned by ConfigureCrtc().
    226   bool configure_crtc_result_;
    227 
    228   // Result value of GetHDCPState().
    229   HDCPState hdcp_state_;
    230 
    231   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
    232 };
    233 
    234 class TestObserver : public OutputConfigurator::Observer {
    235  public:
    236   explicit TestObserver(OutputConfigurator* configurator)
    237       : configurator_(configurator) {
    238     Reset();
    239     configurator_->AddObserver(this);
    240   }
    241   virtual ~TestObserver() {
    242     configurator_->RemoveObserver(this);
    243   }
    244 
    245   int num_changes() const { return num_changes_; }
    246   int num_failures() const { return num_failures_; }
    247   const std::vector<OutputConfigurator::OutputSnapshot>& latest_outputs()
    248       const {
    249     return latest_outputs_;
    250   }
    251   OutputState latest_failed_state() const { return latest_failed_state_; }
    252 
    253   void Reset() {
    254     num_changes_ = 0;
    255     num_failures_ = 0;
    256     latest_outputs_.clear();
    257     latest_failed_state_ = STATE_INVALID;
    258   }
    259 
    260   // OutputConfigurator::Observer overrides:
    261   virtual void OnDisplayModeChanged(
    262       const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
    263     num_changes_++;
    264     latest_outputs_ = outputs;
    265   }
    266 
    267   virtual void OnDisplayModeChangeFailed(OutputState failed_new_state)
    268       OVERRIDE {
    269     num_failures_++;
    270     latest_failed_state_ = failed_new_state;
    271   }
    272 
    273  private:
    274   OutputConfigurator* configurator_;  // Not owned.
    275 
    276   // Number of times that OnDisplayMode*() has been called.
    277   int num_changes_;
    278   int num_failures_;
    279 
    280   // Parameters most recently passed to OnDisplayMode*().
    281   std::vector<OutputConfigurator::OutputSnapshot> latest_outputs_;
    282   OutputState latest_failed_state_;
    283 
    284   DISALLOW_COPY_AND_ASSIGN(TestObserver);
    285 };
    286 
    287 class TestStateController : public OutputConfigurator::StateController {
    288  public:
    289   TestStateController() : state_(STATE_DUAL_EXTENDED) {}
    290   virtual ~TestStateController() {}
    291 
    292   void set_state(OutputState state) { state_ = state; }
    293 
    294   // OutputConfigurator::StateController overrides:
    295   virtual OutputState GetStateForDisplayIds(
    296       const std::vector<int64>& outputs) const OVERRIDE { return state_; }
    297   virtual bool GetResolutionForDisplayId(
    298       int64 display_id,
    299       int *width,
    300       int *height) const OVERRIDE {
    301     return false;
    302   }
    303 
    304  private:
    305   OutputState state_;
    306 
    307   DISALLOW_COPY_AND_ASSIGN(TestStateController);
    308 };
    309 
    310 class TestMirroringController
    311     : public OutputConfigurator::SoftwareMirroringController {
    312  public:
    313   TestMirroringController() : software_mirroring_enabled_(false) {}
    314   virtual ~TestMirroringController() {}
    315 
    316   virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
    317     software_mirroring_enabled_ = enabled;
    318   }
    319 
    320   bool software_mirroring_enabled() const {
    321     return software_mirroring_enabled_;
    322   }
    323 
    324  private:
    325   bool software_mirroring_enabled_;
    326 
    327   DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
    328 };
    329 
    330 class OutputConfiguratorTest : public testing::Test {
    331  public:
    332   // Predefined modes that can be used by outputs.
    333   static const RRMode kSmallModeId;
    334   static const int kSmallModeWidth;
    335   static const int kSmallModeHeight;
    336 
    337   static const RRMode kBigModeId;
    338   static const int kBigModeWidth;
    339   static const int kBigModeHeight;
    340 
    341   OutputConfiguratorTest()
    342       : observer_(&configurator_),
    343         test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
    344   virtual ~OutputConfiguratorTest() {}
    345 
    346   virtual void SetUp() OVERRIDE {
    347     delegate_ = new TestDelegate();
    348     configurator_.SetDelegateForTesting(
    349         scoped_ptr<OutputConfigurator::Delegate>(delegate_));
    350     configurator_.set_state_controller(&state_controller_);
    351     configurator_.set_mirroring_controller(&mirroring_controller_);
    352 
    353     OutputConfigurator::ModeInfo small_mode_info;
    354     small_mode_info.width = kSmallModeWidth;
    355     small_mode_info.height = kSmallModeHeight;
    356 
    357     OutputConfigurator::ModeInfo big_mode_info;
    358     big_mode_info.width = kBigModeWidth;
    359     big_mode_info.height = kBigModeHeight;
    360 
    361     OutputConfigurator::OutputSnapshot* o = &outputs_[0];
    362     o->output = 1;
    363     o->crtc = 10;
    364     o->current_mode = kSmallModeId;
    365     o->native_mode = kSmallModeId;
    366     o->is_internal = true;
    367     o->type = OUTPUT_TYPE_INTERNAL;
    368     o->is_aspect_preserving_scaling = true;
    369     o->mode_infos[kSmallModeId] = small_mode_info;
    370     o->has_display_id = true;
    371     o->display_id = 123;
    372     o->index = 0;
    373 
    374     o = &outputs_[1];
    375     o->output = 2;
    376     o->crtc = 11;
    377     o->current_mode = kBigModeId;
    378     o->native_mode = kBigModeId;
    379     o->is_internal = false;
    380     o->type = OUTPUT_TYPE_HDMI;
    381     o->is_aspect_preserving_scaling = true;
    382     o->mode_infos[kSmallModeId] = small_mode_info;
    383     o->mode_infos[kBigModeId] = big_mode_info;
    384     o->has_display_id = true;
    385     o->display_id = 456;
    386     o->index = 1;
    387 
    388     UpdateOutputs(2, false);
    389   }
    390 
    391  protected:
    392   // Configures |delegate_| to return the first |num_outputs| entries from
    393   // |outputs_|. If |send_events| is true, also sends screen-change and
    394   // output-change events to |configurator_| and triggers the configure
    395   // timeout if one was scheduled.
    396   void UpdateOutputs(size_t num_outputs, bool send_events) {
    397     ASSERT_LE(num_outputs, arraysize(outputs_));
    398     std::vector<OutputConfigurator::OutputSnapshot> outputs;
    399     for (size_t i = 0; i < num_outputs; ++i)
    400       outputs.push_back(outputs_[i]);
    401     delegate_->set_outputs(outputs);
    402 
    403     if (send_events) {
    404       test_api_.SendScreenChangeEvent();
    405       for (size_t i = 0; i < arraysize(outputs_); ++i) {
    406         const OutputConfigurator::OutputSnapshot output = outputs_[i];
    407         bool connected = i < num_outputs;
    408         test_api_.SendOutputChangeEvent(
    409             output.output, output.crtc, output.current_mode, connected);
    410       }
    411       test_api_.TriggerConfigureTimeout();
    412     }
    413   }
    414 
    415   // Initializes |configurator_| with a single internal display.
    416   void InitWithSingleOutput() {
    417     UpdateOutputs(1, false);
    418     EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    419     configurator_.Init(false);
    420     EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    421     configurator_.Start(0);
    422     EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
    423                           GetFramebufferAction(kSmallModeWidth,
    424                               kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
    425                           GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    426                                         outputs_[0].output).c_str(),
    427                           kForceDPMS, kUngrab, kProjectingOff, NULL),
    428               delegate_->GetActionsAndClear());
    429   }
    430 
    431   base::MessageLoop message_loop_;
    432   TestStateController state_controller_;
    433   TestMirroringController mirroring_controller_;
    434   OutputConfigurator configurator_;
    435   TestObserver observer_;
    436   TestDelegate* delegate_;  // not owned
    437   OutputConfigurator::TestApi test_api_;
    438 
    439   OutputConfigurator::OutputSnapshot outputs_[2];
    440 
    441  private:
    442   DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
    443 };
    444 
    445 const RRMode OutputConfiguratorTest::kSmallModeId = 20;
    446 const int OutputConfiguratorTest::kSmallModeWidth = 1366;
    447 const int OutputConfiguratorTest::kSmallModeHeight = 768;
    448 
    449 const RRMode OutputConfiguratorTest::kBigModeId = 21;
    450 const int OutputConfiguratorTest::kBigModeWidth = 2560;
    451 const int OutputConfiguratorTest::kBigModeHeight = 1600;
    452 
    453 }  // namespace
    454 
    455 TEST_F(OutputConfiguratorTest, FindOutputModeMatchingSize) {
    456   OutputConfigurator::OutputSnapshot output;
    457 
    458   // Fields are width, height, interlaced, refresh rate.
    459   output.mode_infos[11] = OutputConfigurator::ModeInfo(1920, 1200, false, 60.0);
    460   // Different rates.
    461   output.mode_infos[12] = OutputConfigurator::ModeInfo(1920, 1080, false, 30.0);
    462   output.mode_infos[13] = OutputConfigurator::ModeInfo(1920, 1080, false, 50.0);
    463   output.mode_infos[14] = OutputConfigurator::ModeInfo(1920, 1080, false, 40.0);
    464   output.mode_infos[15] = OutputConfigurator::ModeInfo(1920, 1080, false, 0.0);
    465   // Interlaced vs non-interlaced.
    466   output.mode_infos[16] = OutputConfigurator::ModeInfo(1280, 720, true, 60.0);
    467   output.mode_infos[17] = OutputConfigurator::ModeInfo(1280, 720, false, 40.0);
    468   // Interlaced only.
    469   output.mode_infos[18] = OutputConfigurator::ModeInfo(1024, 768, true, 0.0);
    470   output.mode_infos[19] = OutputConfigurator::ModeInfo(1024, 768, true, 40.0);
    471   output.mode_infos[20] = OutputConfigurator::ModeInfo(1024, 768, true, 60.0);
    472   // Mixed.
    473   output.mode_infos[21] = OutputConfigurator::ModeInfo(1024, 600, true, 60.0);
    474   output.mode_infos[22] = OutputConfigurator::ModeInfo(1024, 600, false, 40.0);
    475   output.mode_infos[23] = OutputConfigurator::ModeInfo(1024, 600, false, 50.0);
    476   // Just one interlaced mode.
    477   output.mode_infos[24] = OutputConfigurator::ModeInfo(640, 480, true, 60.0);
    478   // Refresh rate not available.
    479   output.mode_infos[25] = OutputConfigurator::ModeInfo(320, 200, false, 0.0);
    480 
    481   EXPECT_EQ(11u, OutputConfigurator::FindOutputModeMatchingSize(output,
    482                                                                 1920, 1200));
    483 
    484   // Should pick highest refresh rate.
    485   EXPECT_EQ(13u, OutputConfigurator::FindOutputModeMatchingSize(output,
    486                                                                 1920, 1080));
    487 
    488   // Should pick non-interlaced mode.
    489   EXPECT_EQ(17u, OutputConfigurator::FindOutputModeMatchingSize(output,
    490                                                                 1280, 720));
    491 
    492   // Interlaced only. Should pick one with the highest refresh rate in
    493   // interlaced mode.
    494   EXPECT_EQ(20u, OutputConfigurator::FindOutputModeMatchingSize(output,
    495                                                                 1024, 768));
    496 
    497   // Mixed: Should pick one with the highest refresh rate in
    498   // interlaced mode.
    499   EXPECT_EQ(23u, OutputConfigurator::FindOutputModeMatchingSize(output,
    500                                                                 1024, 600));
    501 
    502   // Just one interlaced mode.
    503   EXPECT_EQ(24u, OutputConfigurator::FindOutputModeMatchingSize(output,
    504                                                                 640, 480));
    505 
    506   // Refresh rate not available.
    507   EXPECT_EQ(25u, OutputConfigurator::FindOutputModeMatchingSize(output,
    508                                                                 320, 200));
    509 
    510   // No mode found.
    511   EXPECT_EQ(0u, OutputConfigurator::FindOutputModeMatchingSize(output,
    512                                                                1440, 900));
    513 }
    514 
    515 TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
    516   InitWithSingleOutput();
    517 
    518   // Connect a second output and check that the configurator enters
    519   // extended mode.
    520   observer_.Reset();
    521   state_controller_.set_state(STATE_DUAL_EXTENDED);
    522   UpdateOutputs(2, true);
    523   const int kDualHeight =
    524       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
    525   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    526                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    527                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    528                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    529                             outputs_[0].output).c_str(),
    530                         GetCrtcAction(outputs_[1].crtc, 0,
    531                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    532                             kBigModeId, outputs_[1].output).c_str(),
    533                         kUngrab, kProjectingOn, NULL),
    534             delegate_->GetActionsAndClear());
    535   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    536   EXPECT_EQ(1, observer_.num_changes());
    537 
    538   observer_.Reset();
    539   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    540   EXPECT_EQ(JoinActions(kGrab,
    541                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    542                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    543                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    544                             outputs_[0].output).c_str(),
    545                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    546                             outputs_[1].output).c_str(),
    547                         kUngrab, NULL),
    548             delegate_->GetActionsAndClear());
    549   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    550   EXPECT_EQ(1, observer_.num_changes());
    551 
    552   // Disconnect the second output.
    553   observer_.Reset();
    554   UpdateOutputs(1, true);
    555   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    556                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    557                             outputs_[0].crtc, 0).c_str(),
    558                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    559                             outputs_[0].output).c_str(),
    560                         kUngrab, kProjectingOff, NULL),
    561             delegate_->GetActionsAndClear());
    562   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    563   EXPECT_EQ(1, observer_.num_changes());
    564 
    565   // Get rid of shared modes to force software mirroring.
    566   outputs_[1].mode_infos.erase(kSmallModeId);
    567   state_controller_.set_state(STATE_DUAL_EXTENDED);
    568   UpdateOutputs(2, true);
    569   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    570                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    571                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    572                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    573                             outputs_[0].output).c_str(),
    574                         GetCrtcAction(outputs_[1].crtc, 0,
    575                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    576                             kBigModeId, outputs_[1].output).c_str(),
    577                         kUngrab, kProjectingOn, NULL),
    578             delegate_->GetActionsAndClear());
    579   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    580 
    581   observer_.Reset();
    582   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    583   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
    584   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    585   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    586   EXPECT_EQ(1, observer_.num_changes());
    587 
    588   // Setting STATE_DUAL_MIRROR should try to reconfigure.
    589   observer_.Reset();
    590   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    591   EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
    592   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    593   EXPECT_EQ(1, observer_.num_changes());
    594 
    595   // Set back to software mirror mode.
    596   observer_.Reset();
    597   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    598   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
    599             delegate_->GetActionsAndClear());
    600   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    601   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    602   EXPECT_EQ(1, observer_.num_changes());
    603 
    604   // Disconnect the second output.
    605   observer_.Reset();
    606   UpdateOutputs(1, true);
    607   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    608                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    609                             outputs_[0].crtc, 0).c_str(),
    610                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    611                             outputs_[0].output).c_str(),
    612                         kUngrab, kProjectingOff, NULL),
    613             delegate_->GetActionsAndClear());
    614   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    615   EXPECT_EQ(1, observer_.num_changes());
    616 }
    617 
    618 TEST_F(OutputConfiguratorTest, SetDisplayPower) {
    619   InitWithSingleOutput();
    620 
    621   state_controller_.set_state(STATE_DUAL_MIRROR);
    622   observer_.Reset();
    623   UpdateOutputs(2, true);
    624   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    625                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    626                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    627                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    628                             outputs_[0].output).c_str(),
    629                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    630                             outputs_[1].output).c_str(),
    631                         kUngrab, kProjectingOn, NULL),
    632             delegate_->GetActionsAndClear());
    633   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    634   EXPECT_EQ(1, observer_.num_changes());
    635 
    636   // Turning off the internal display should switch the external display to
    637   // its native mode.
    638   observer_.Reset();
    639   configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
    640                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    641   EXPECT_EQ(JoinActions(kGrab,
    642                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
    643                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    644                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    645                             outputs_[0].output).c_str(),
    646                         GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
    647                             outputs_[1].output).c_str(),
    648                         kForceDPMS, kUngrab, NULL),
    649             delegate_->GetActionsAndClear());
    650   EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
    651   EXPECT_EQ(1, observer_.num_changes());
    652 
    653   // When all displays are turned off, the framebuffer should switch back
    654   // to the mirrored size.
    655   observer_.Reset();
    656   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    657                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    658   EXPECT_EQ(JoinActions(kGrab,
    659                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    660                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    661                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    662                             outputs_[0].output).c_str(),
    663                         GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
    664                             outputs_[1].output).c_str(),
    665                         kUngrab, NULL),
    666             delegate_->GetActionsAndClear());
    667   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
    668   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    669   EXPECT_EQ(1, observer_.num_changes());
    670 
    671   // Turn all displays on and check that mirroring is still used.
    672   observer_.Reset();
    673   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
    674                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    675   EXPECT_EQ(JoinActions(kGrab,
    676                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    677                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    678                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    679                             outputs_[0].output).c_str(),
    680                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    681                             outputs_[1].output).c_str(),
    682                         kForceDPMS, kUngrab, NULL),
    683             delegate_->GetActionsAndClear());
    684   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
    685   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    686   EXPECT_EQ(1, observer_.num_changes());
    687 
    688   // Get rid of shared modes to force software mirroring.
    689   outputs_[1].mode_infos.erase(kSmallModeId);
    690   state_controller_.set_state(STATE_DUAL_MIRROR);
    691   observer_.Reset();
    692   UpdateOutputs(2, true);
    693   const int kDualHeight =
    694       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
    695   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    696                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    697                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    698                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    699                             outputs_[0].output).c_str(),
    700                         GetCrtcAction(outputs_[1].crtc, 0,
    701                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    702                             kBigModeId, outputs_[1].output).c_str(),
    703                         kUngrab, kProjectingOn, NULL),
    704             delegate_->GetActionsAndClear());
    705   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    706   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    707   EXPECT_EQ(1, observer_.num_changes());
    708 
    709   // Turning off the internal display should switch the external display to
    710   // its native mode.
    711   observer_.Reset();
    712   configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
    713                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    714   EXPECT_EQ(JoinActions(kGrab,
    715                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
    716                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    717                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    718                             outputs_[0].output).c_str(),
    719                         GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
    720                             outputs_[1].output).c_str(),
    721                         kForceDPMS, kUngrab, NULL),
    722             delegate_->GetActionsAndClear());
    723   EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
    724   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    725   EXPECT_EQ(1, observer_.num_changes());
    726 
    727   // When all displays are turned off, the framebuffer should switch back
    728   // to the extended + software mirroring.
    729   observer_.Reset();
    730   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    731                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    732   EXPECT_EQ(JoinActions(kGrab,
    733                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    734                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    735                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    736                             outputs_[0].output).c_str(),
    737                         GetCrtcAction(outputs_[1].crtc, 0,
    738                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    739                             0, outputs_[1].output).c_str(),
    740                         kUngrab, NULL),
    741             delegate_->GetActionsAndClear());
    742   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    743   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    744   EXPECT_EQ(1, observer_.num_changes());
    745 
    746   // Turn all displays on and check that mirroring is still used.
    747   observer_.Reset();
    748   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
    749                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    750   EXPECT_EQ(JoinActions(kGrab,
    751                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    752                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    753                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    754                             outputs_[0].output).c_str(),
    755                         GetCrtcAction(outputs_[1].crtc, 0,
    756                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    757                             kBigModeId, outputs_[1].output).c_str(),
    758                         kForceDPMS, kUngrab, NULL),
    759             delegate_->GetActionsAndClear());
    760   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    761   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    762   EXPECT_EQ(1, observer_.num_changes());
    763 }
    764 
    765 TEST_F(OutputConfiguratorTest, SuspendAndResume) {
    766   InitWithSingleOutput();
    767 
    768   // No preparation is needed before suspending when the display is already
    769   // on.  The configurator should still reprobe on resume in case a display
    770   // was connected while suspended.
    771   configurator_.SuspendDisplays();
    772   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    773   configurator_.ResumeDisplays();
    774   EXPECT_EQ(JoinActions(kGrab,
    775                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    776                             outputs_[0].crtc, 0).c_str(),
    777                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    778                             outputs_[0].output).c_str(),
    779                         kForceDPMS, kUngrab, NULL),
    780             delegate_->GetActionsAndClear());
    781 
    782   // Now turn the display off before suspending and check that the
    783   // configurator turns it back on and syncs with the server.
    784   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    785                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    786   EXPECT_EQ(JoinActions(kGrab,
    787                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    788                             outputs_[0].crtc, 0).c_str(),
    789                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    790                             outputs_[0].output).c_str(),
    791                         kUngrab, NULL),
    792             delegate_->GetActionsAndClear());
    793 
    794   configurator_.SuspendDisplays();
    795   EXPECT_EQ(JoinActions(kGrab,
    796                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    797                             outputs_[0].crtc, 0).c_str(),
    798                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    799                             outputs_[0].output).c_str(),
    800                         kForceDPMS, kUngrab, kSync, NULL),
    801             delegate_->GetActionsAndClear());
    802 
    803   configurator_.ResumeDisplays();
    804   EXPECT_EQ(JoinActions(kGrab,
    805                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    806                             outputs_[0].crtc, 0).c_str(),
    807                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    808                             outputs_[0].output).c_str(),
    809                         kForceDPMS, kUngrab, NULL),
    810             delegate_->GetActionsAndClear());
    811 
    812   // If a second, external display is connected, the displays shouldn't be
    813   // powered back on before suspending.
    814   state_controller_.set_state(STATE_DUAL_MIRROR);
    815   UpdateOutputs(2, true);
    816   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    817                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    818                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    819                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    820                             outputs_[0].output).c_str(),
    821                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    822                             outputs_[1].output).c_str(),
    823                         kUngrab, kProjectingOn, NULL),
    824             delegate_->GetActionsAndClear());
    825 
    826   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    827                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    828   EXPECT_EQ(JoinActions(kGrab,
    829                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    830                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    831                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    832                             outputs_[0].output).c_str(),
    833                         GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
    834                             outputs_[1].output).c_str(),
    835                         kUngrab, NULL),
    836             delegate_->GetActionsAndClear());
    837 
    838   configurator_.SuspendDisplays();
    839   EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
    840             delegate_->GetActionsAndClear());
    841 
    842   // If a display is disconnected while suspended, the configurator should
    843   // pick up the change.
    844   UpdateOutputs(1, false);
    845   configurator_.ResumeDisplays();
    846   EXPECT_EQ(JoinActions(kGrab,
    847                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    848                             outputs_[0].crtc, 0).c_str(),
    849                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    850                             outputs_[0].output).c_str(),
    851                         kUngrab, NULL),
    852             delegate_->GetActionsAndClear());
    853 }
    854 
    855 TEST_F(OutputConfiguratorTest, Headless) {
    856   UpdateOutputs(0, false);
    857   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    858   configurator_.Init(false);
    859   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    860   configurator_.Start(0);
    861   EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
    862                         kProjectingOff, NULL),
    863             delegate_->GetActionsAndClear());
    864 
    865   // Not much should happen when the display power state is changed while
    866   // no displays are connected.
    867   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    868                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    869   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
    870   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
    871                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    872   EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
    873             delegate_->GetActionsAndClear());
    874 
    875   // Connect an external display and check that it's configured correctly.
    876   outputs_[0] = outputs_[1];
    877   UpdateOutputs(1, true);
    878   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    879                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
    880                             outputs_[0].crtc, 0).c_str(),
    881                         GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
    882                             outputs_[0].output).c_str(),
    883                         kUngrab, kProjectingOff, NULL),
    884             delegate_->GetActionsAndClear());
    885 }
    886 
    887 TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
    888   UpdateOutputs(2, false);
    889   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    890   configurator_.Init(false);
    891   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    892 
    893   state_controller_.set_state(STATE_DUAL_MIRROR);
    894   configurator_.Start(0);
    895   EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
    896                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    897                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    898                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    899                             outputs_[0].output).c_str(),
    900                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    901                             outputs_[1].output).c_str(),
    902                         kForceDPMS, kUngrab, kProjectingOn, NULL),
    903             delegate_->GetActionsAndClear());
    904 }
    905 
    906 TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
    907   UpdateOutputs(0, false);
    908   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    909   configurator_.Init(false);
    910   configurator_.Start(0);
    911   observer_.Reset();
    912   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
    913   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
    914   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    915   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    916   EXPECT_EQ(1, observer_.num_changes());
    917   EXPECT_EQ(3, observer_.num_failures());
    918 
    919   UpdateOutputs(1, true);
    920   observer_.Reset();
    921   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
    922   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
    923   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    924   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    925   EXPECT_EQ(1, observer_.num_changes());
    926   EXPECT_EQ(3, observer_.num_failures());
    927 
    928   state_controller_.set_state(STATE_DUAL_EXTENDED);
    929   UpdateOutputs(2, true);
    930   observer_.Reset();
    931   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
    932   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
    933   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    934   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    935   EXPECT_EQ(2, observer_.num_changes());
    936   EXPECT_EQ(2, observer_.num_failures());
    937 }
    938 
    939 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
    940   outputs_[0].has_display_id = false;
    941   UpdateOutputs(2, false);
    942   configurator_.Init(false);
    943   state_controller_.set_state(STATE_DUAL_MIRROR);
    944   configurator_.Start(0);
    945   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    946 }
    947 
    948 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
    949   outputs_[0].has_display_id = true;
    950   UpdateOutputs(2, false);
    951   configurator_.Init(false);
    952   state_controller_.set_state(STATE_DUAL_MIRROR);
    953   configurator_.Start(0);
    954   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
    955 }
    956 
    957 TEST_F(OutputConfiguratorTest, AvoidUnnecessaryProbes) {
    958   InitWithSingleOutput();
    959 
    960   // X sends several events just after the configurator starts. Check that
    961   // the output change events don't trigger an additional probe, which can
    962   // block the UI thread.
    963   test_api_.SendScreenChangeEvent();
    964   EXPECT_EQ(kUpdateXRandR, delegate_->GetActionsAndClear());
    965 
    966   test_api_.SendOutputChangeEvent(
    967       outputs_[0].output, outputs_[0].crtc, outputs_[0].current_mode, true);
    968   test_api_.SendOutputChangeEvent(
    969       outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
    970   EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
    971   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    972 
    973   // Send an event stating that the second output is connected and check
    974   // that it gets updated.
    975   state_controller_.set_state(STATE_DUAL_MIRROR);
    976   UpdateOutputs(2, false);
    977   test_api_.SendOutputChangeEvent(
    978       outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, true);
    979   EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
    980   EXPECT_EQ(JoinActions(kGrab,
    981                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    982                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    983                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    984                             outputs_[0].output).c_str(),
    985                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    986                             outputs_[1].output).c_str(),
    987                         kUngrab, kProjectingOn, NULL),
    988             delegate_->GetActionsAndClear());
    989 
    990   // An event about the second output changing modes should trigger another
    991   // reconfigure.
    992   test_api_.SendOutputChangeEvent(
    993       outputs_[1].output, outputs_[1].crtc, outputs_[1].native_mode, true);
    994   EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
    995   EXPECT_EQ(JoinActions(kGrab,
    996                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    997                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    998                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    999                             outputs_[0].output).c_str(),
   1000                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
   1001                             outputs_[1].output).c_str(),
   1002                         kUngrab, kProjectingOn, NULL),
   1003             delegate_->GetActionsAndClear());
   1004 
   1005   // Disconnect the second output.
   1006   UpdateOutputs(1, true);
   1007   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
   1008                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
   1009                             outputs_[0].crtc, 0).c_str(),
   1010                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
   1011                             outputs_[0].output).c_str(),
   1012                         kUngrab, kProjectingOff, NULL),
   1013             delegate_->GetActionsAndClear());
   1014 
   1015   // An additional event about the second output being disconnected should
   1016   // be ignored.
   1017   test_api_.SendOutputChangeEvent(
   1018       outputs_[1].output, outputs_[1].crtc, outputs_[1].current_mode, false);
   1019   EXPECT_FALSE(test_api_.TriggerConfigureTimeout());
   1020   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   1021 
   1022   // Tell the delegate to report failure, which should result in the
   1023   // second output sticking with its native mode.
   1024   delegate_->set_configure_crtc_result(false);
   1025   UpdateOutputs(2, true);
   1026   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
   1027                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
   1028                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
   1029                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
   1030                             outputs_[0].output).c_str(),
   1031                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
   1032                             outputs_[1].output).c_str(),
   1033                         kUngrab, kProjectingOn, NULL),
   1034             delegate_->GetActionsAndClear());
   1035 
   1036   // An change event reporting a mode change on the second output should
   1037   // trigger another reconfigure.
   1038   delegate_->set_configure_crtc_result(true);
   1039   test_api_.SendOutputChangeEvent(
   1040       outputs_[1].output, outputs_[1].crtc, outputs_[1].mirror_mode, true);
   1041   EXPECT_TRUE(test_api_.TriggerConfigureTimeout());
   1042   EXPECT_EQ(JoinActions(kGrab,
   1043                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
   1044                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
   1045                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
   1046                             outputs_[0].output).c_str(),
   1047                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
   1048                             outputs_[1].output).c_str(),
   1049                         kUngrab, kProjectingOn, NULL),
   1050             delegate_->GetActionsAndClear());
   1051 }
   1052 
   1053 TEST_F(OutputConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) {
   1054   InitWithSingleOutput();
   1055   const std::vector<OutputConfigurator::OutputSnapshot>* cached =
   1056       &test_api_.cached_outputs();
   1057   ASSERT_EQ(static_cast<size_t>(1), cached->size());
   1058   EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
   1059 
   1060   // After connecting a second output, check that it shows up in
   1061   // |cached_outputs_| even if an invalid state is requested.
   1062   state_controller_.set_state(STATE_SINGLE);
   1063   UpdateOutputs(2, true);
   1064   cached = &test_api_.cached_outputs();
   1065   ASSERT_EQ(static_cast<size_t>(2), cached->size());
   1066   EXPECT_EQ(outputs_[0].current_mode, (*cached)[0].current_mode);
   1067   EXPECT_EQ(outputs_[1].current_mode, (*cached)[1].current_mode);
   1068 }
   1069 
   1070 TEST_F(OutputConfiguratorTest, PanelFitting) {
   1071   // Configure the internal display to support only the big mode and the
   1072   // external display to support only the small mode.
   1073   outputs_[0].current_mode = kBigModeId;
   1074   outputs_[0].native_mode = kBigModeId;
   1075   outputs_[0].mode_infos.clear();
   1076   outputs_[0].mode_infos[kBigModeId] = OutputConfigurator::ModeInfo(
   1077       kBigModeWidth, kBigModeHeight, false, 60.0);
   1078 
   1079   outputs_[1].current_mode = kSmallModeId;
   1080   outputs_[1].native_mode = kSmallModeId;
   1081   outputs_[1].mode_infos.clear();
   1082   outputs_[1].mode_infos[kSmallModeId] = OutputConfigurator::ModeInfo(
   1083       kSmallModeWidth, kSmallModeHeight, false, 60.0);
   1084 
   1085   // The small mode should be added to the internal output when requesting
   1086   // mirrored mode.
   1087   UpdateOutputs(2, false);
   1088   state_controller_.set_state(STATE_DUAL_MIRROR);
   1089   configurator_.Init(true /* is_panel_fitting_enabled */);
   1090   configurator_.Start(0);
   1091   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
   1092   EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
   1093                         GetAddOutputModeAction(
   1094                             outputs_[0].output, kSmallModeId).c_str(),
   1095                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
   1096                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
   1097                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
   1098                             outputs_[0].output).c_str(),
   1099                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
   1100                             outputs_[1].output).c_str(),
   1101                         kForceDPMS, kUngrab, kProjectingOn, NULL),
   1102             delegate_->GetActionsAndClear());
   1103 
   1104   // Both outputs should be using the small mode.
   1105   ASSERT_EQ(1, observer_.num_changes());
   1106   ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size());
   1107   EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].mirror_mode);
   1108   EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[0].current_mode);
   1109   EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].mirror_mode);
   1110   EXPECT_EQ(kSmallModeId, observer_.latest_outputs()[1].current_mode);
   1111 
   1112   // Also check that the newly-added small mode is present in the internal
   1113   // snapshot that was passed to the observer (http://crbug.com/289159).
   1114   const OutputConfigurator::ModeInfo* info = OutputConfigurator::GetModeInfo(
   1115       observer_.latest_outputs()[0], kSmallModeId);
   1116   ASSERT_TRUE(info);
   1117   EXPECT_EQ(kSmallModeWidth, info->width);
   1118   EXPECT_EQ(kSmallModeHeight, info->height);
   1119 }
   1120 
   1121 TEST_F(OutputConfiguratorTest, OutputProtection) {
   1122   configurator_.Init(false);
   1123   configurator_.Start(0);
   1124   EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
   1125 
   1126   OutputConfigurator::OutputProtectionClientId id =
   1127       configurator_.RegisterOutputProtectionClient();
   1128   EXPECT_NE(0u, id);
   1129 
   1130   // One output.
   1131   UpdateOutputs(1, true);
   1132   EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
   1133   uint32_t link_mask = 0;
   1134   uint32_t protection_mask = 0;
   1135   EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
   1136                                                         outputs_[0].display_id,
   1137                                                         &link_mask,
   1138                                                         &protection_mask));
   1139   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask);
   1140   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
   1141             protection_mask);
   1142   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   1143 
   1144   // Two outputs.
   1145   UpdateOutputs(2, true);
   1146   EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
   1147   EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
   1148                                                         outputs_[1].display_id,
   1149                                                         &link_mask,
   1150                                                         &protection_mask));
   1151   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI),
   1152             link_mask);
   1153   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
   1154             protection_mask);
   1155   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   1156 
   1157   EXPECT_TRUE(
   1158       configurator_.EnableOutputProtection(id,
   1159                                            outputs_[1].display_id,
   1160                                            OUTPUT_PROTECTION_METHOD_HDCP));
   1161   EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_DESIRED),
   1162             delegate_->GetActionsAndClear());
   1163 
   1164   // Enable protection.
   1165   delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
   1166   EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(id,
   1167                                                         outputs_[1].display_id,
   1168                                                         &link_mask,
   1169                                                         &protection_mask));
   1170   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
   1171   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP),
   1172             protection_mask);
   1173   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
   1174 
   1175   // Protections should be disabled after unregister.
   1176   configurator_.UnregisterOutputProtectionClient(id);
   1177   EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output, HDCP_STATE_UNDESIRED),
   1178             delegate_->GetActionsAndClear());
   1179 }
   1180 
   1181 TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) {
   1182   OutputConfigurator::OutputProtectionClientId client1 =
   1183       configurator_.RegisterOutputProtectionClient();
   1184   OutputConfigurator::OutputProtectionClientId client2 =
   1185       configurator_.RegisterOutputProtectionClient();
   1186   EXPECT_NE(client1, client2);
   1187 
   1188   configurator_.Init(false);
   1189   configurator_.Start(0);
   1190   UpdateOutputs(2, true);
   1191   EXPECT_NE(kNoActions, delegate_->GetActionsAndClear());
   1192 
   1193   // Clients never know state enableness for methods that they didn't request.
   1194   EXPECT_TRUE(
   1195       configurator_.EnableOutputProtection(client1,
   1196                                            outputs_[1].display_id,
   1197                                            OUTPUT_PROTECTION_METHOD_HDCP));
   1198   EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
   1199                                   HDCP_STATE_DESIRED).c_str(),
   1200             delegate_->GetActionsAndClear());
   1201   delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
   1202 
   1203   uint32_t link_mask = 0;
   1204   uint32_t protection_mask = 0;
   1205   EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client1,
   1206                                                         outputs_[1].display_id,
   1207                                                         &link_mask,
   1208                                                         &protection_mask));
   1209   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
   1210   EXPECT_EQ(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask);
   1211 
   1212   EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(client2,
   1213                                                         outputs_[1].display_id,
   1214                                                         &link_mask,
   1215                                                         &protection_mask));
   1216   EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
   1217   EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask);
   1218 
   1219   // Protections will be disabled only if no more clients request them.
   1220   EXPECT_TRUE(
   1221       configurator_.EnableOutputProtection(client2,
   1222                                            outputs_[1].display_id,
   1223                                            OUTPUT_PROTECTION_METHOD_NONE));
   1224   EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
   1225                                   HDCP_STATE_DESIRED).c_str(),
   1226             delegate_->GetActionsAndClear());
   1227   EXPECT_TRUE(
   1228       configurator_.EnableOutputProtection(client1,
   1229                                            outputs_[1].display_id,
   1230                                            OUTPUT_PROTECTION_METHOD_NONE));
   1231   EXPECT_EQ(GetSetHDCPStateAction(outputs_[1].output,
   1232                                   HDCP_STATE_UNDESIRED).c_str(),
   1233             delegate_->GetActionsAndClear());
   1234 }
   1235 
   1236 TEST_F(OutputConfiguratorTest, CTMForMultiScreens) {
   1237   outputs_[0].touch_device_id = 1;
   1238   outputs_[1].touch_device_id = 2;
   1239 
   1240   UpdateOutputs(2, false);
   1241   configurator_.Init(false);
   1242   state_controller_.set_state(STATE_DUAL_EXTENDED);
   1243   configurator_.Start(0);
   1244 
   1245   const int kDualHeight =
   1246       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
   1247   const int kDualWidth = kBigModeWidth;
   1248 
   1249   OutputConfigurator::CoordinateTransformation ctm1 = delegate_->get_ctm(1);
   1250   OutputConfigurator::CoordinateTransformation ctm2 = delegate_->get_ctm(2);
   1251 
   1252   EXPECT_EQ(kSmallModeHeight - 1, round((kDualHeight - 1) * ctm1.y_scale));
   1253   EXPECT_EQ(0, round((kDualHeight - 1) * ctm1.y_offset));
   1254 
   1255   EXPECT_EQ(kBigModeHeight - 1, round((kDualHeight - 1) * ctm2.y_scale));
   1256   EXPECT_EQ(kSmallModeHeight + OutputConfigurator::kVerticalGap,
   1257             round((kDualHeight - 1) * ctm2.y_offset));
   1258 
   1259   EXPECT_EQ(kSmallModeWidth - 1, round((kDualWidth - 1) * ctm1.x_scale));
   1260   EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset));
   1261 
   1262   EXPECT_EQ(kBigModeWidth - 1, round((kDualWidth - 1) * ctm2.x_scale));
   1263   EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset));
   1264 }
   1265 
   1266 }  // namespace chromeos
   1267