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 <cstdarg>
      8 #include <map>
      9 #include <string>
     10 #include <vector>
     11 
     12 #include "base/basictypes.h"
     13 #include "base/compiler_specific.h"
     14 #include "base/message_loop/message_loop.h"
     15 #include "base/strings/stringprintf.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 namespace chromeos {
     19 
     20 namespace {
     21 
     22 // Strings returned by TestDelegate::GetActionsAndClear() to describe various
     23 // actions that were performed.
     24 const char kInitXRandR[] = "init";
     25 const char kUpdateXRandR[] = "update";
     26 const char kGrab[] = "grab";
     27 const char kUngrab[] = "ungrab";
     28 const char kSync[] = "sync";
     29 const char kForceDPMS[] = "dpms";
     30 const char kProjectingOn[] = "projecting";
     31 const char kProjectingOff[] = "not_projecting";
     32 
     33 // String returned by TestDelegate::GetActionsAndClear() if no actions were
     34 // requested.
     35 const char kNoActions[] = "";
     36 
     37 // Returns a string describing a TestDelegate::SetBackgroundColor() call.
     38 std::string GetBackgroundAction(uint32 color_argb) {
     39   return base::StringPrintf("background(0x%x)", color_argb);
     40 }
     41 
     42 // Returns a string describing a TestDelegate::ConfigureCrtc() call.
     43 std::string GetCrtcAction(RRCrtc crtc,
     44                           int x,
     45                           int y,
     46                           RRMode mode,
     47                           RROutput output) {
     48   return base::StringPrintf("crtc(crtc=%lu,x=%d,y=%d,mode=%lu,output=%lu)",
     49                             crtc, x, y, mode, output);
     50 }
     51 
     52 // Returns a string describing a TestDelegate::CreateFramebuffer() call.
     53 std::string GetFramebufferAction(int width,
     54                                  int height,
     55                                  RRCrtc crtc1,
     56                                  RRCrtc crtc2) {
     57   return base::StringPrintf(
     58       "framebuffer(width=%d,height=%d,crtc1=%lu,crtc2=%lu)",
     59       width, height, crtc1, crtc2);
     60 }
     61 
     62 // Returns a string describing a TestDelegate::ConfigureCTM() call.
     63 std::string GetCTMAction(
     64     int device_id,
     65     const OutputConfigurator::CoordinateTransformation& ctm) {
     66   return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))", device_id,
     67       ctm.x_scale, ctm.x_offset, ctm.y_scale, ctm.y_offset);
     68 }
     69 
     70 // Joins a sequence of strings describing actions (e.g. kScreenDim) such
     71 // that they can be compared against a string returned by
     72 // TestDelegate::GetActionsAndClear().  The list of actions must be
     73 // terminated by a NULL pointer.
     74 std::string JoinActions(const char* action, ...) {
     75   std::string actions;
     76 
     77   va_list arg_list;
     78   va_start(arg_list, action);
     79   while (action) {
     80     if (!actions.empty())
     81       actions += ",";
     82     actions += action;
     83     action = va_arg(arg_list, const char*);
     84   }
     85   va_end(arg_list);
     86   return actions;
     87 }
     88 
     89 class TestDelegate : public OutputConfigurator::Delegate {
     90  public:
     91   static const int kXRandREventBase = 10;
     92 
     93   TestDelegate() {}
     94   virtual ~TestDelegate() {}
     95 
     96   void set_outputs(
     97       const std::vector<OutputConfigurator::OutputSnapshot>& outputs) {
     98     outputs_ = outputs;
     99   }
    100 
    101   // Returns a comma-separated string describing the actions that were
    102   // requested since the previous call to GetActionsAndClear() (i.e.
    103   // results are non-repeatable).
    104   std::string GetActionsAndClear() {
    105     std::string actions = actions_;
    106     actions_.clear();
    107     return actions;
    108   }
    109 
    110   // Adds a mode to be returned by GetModeDetails().
    111   void AddMode(RRMode mode, int width, int height, bool interlaced) {
    112     modes_[mode] = ModeDetails(width, height, interlaced);
    113   }
    114 
    115   // OutputConfigurator::Delegate overrides:
    116   virtual void SetPanelFittingEnabled(bool enabled) OVERRIDE {}
    117   virtual void InitXRandRExtension(int* event_base) OVERRIDE {
    118     AppendAction(kInitXRandR);
    119     *event_base = kXRandREventBase;
    120   }
    121   virtual void UpdateXRandRConfiguration(
    122       const base::NativeEvent& event) OVERRIDE { AppendAction(kUpdateXRandR); }
    123   virtual void GrabServer() OVERRIDE { AppendAction(kGrab); }
    124   virtual void UngrabServer() OVERRIDE { AppendAction(kUngrab); }
    125   virtual void SyncWithServer() OVERRIDE { AppendAction(kSync); }
    126   virtual void SetBackgroundColor(uint32 color_argb) OVERRIDE {
    127     AppendAction(GetBackgroundAction(color_argb));
    128   }
    129   virtual void ForceDPMSOn() OVERRIDE { AppendAction(kForceDPMS); }
    130   virtual std::vector<OutputConfigurator::OutputSnapshot> GetOutputs(
    131       const OutputConfigurator::StateController* controller) OVERRIDE {
    132     return outputs_;
    133   }
    134   virtual bool GetModeDetails(
    135       RRMode mode,
    136       int* width,
    137       int* height,
    138       bool* interlaced) OVERRIDE {
    139     std::map<RRMode, ModeDetails>::const_iterator it = modes_.find(mode);
    140     if (it == modes_.end())
    141       return false;
    142 
    143     if (width)
    144       *width = it->second.width;
    145     if (height)
    146       *height = it->second.height;
    147     if (interlaced)
    148       *interlaced = it->second.interlaced;
    149     return true;
    150   }
    151   virtual bool ConfigureCrtc(RRCrtc crtc,
    152                              RRMode mode,
    153                              RROutput output,
    154                              int x,
    155                              int y) OVERRIDE {
    156     AppendAction(GetCrtcAction(crtc, x, y, mode, output));
    157     return true;
    158   }
    159   virtual void CreateFrameBuffer(
    160       int width,
    161       int height,
    162       const std::vector<OutputConfigurator::OutputSnapshot>& outputs) OVERRIDE {
    163     AppendAction(
    164         GetFramebufferAction(width,
    165                              height,
    166                              outputs.size() >= 1 ? outputs[0].crtc : 0,
    167                              outputs.size() >= 2 ? outputs[1].crtc : 0));
    168   }
    169   virtual void ConfigureCTM(
    170       int touch_device_id,
    171       const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
    172     AppendAction(GetCTMAction(touch_device_id, ctm));
    173   }
    174   virtual void SendProjectingStateToPowerManager(bool projecting) OVERRIDE {
    175     AppendAction(projecting ? kProjectingOn : kProjectingOff);
    176   }
    177 
    178  private:
    179   struct ModeDetails {
    180     ModeDetails() : width(0), height(0), interlaced(false) {}
    181     ModeDetails(int width, int height, bool interlaced)
    182         : width(width),
    183           height(height),
    184           interlaced(interlaced) {}
    185 
    186     int width;
    187     int height;
    188     bool interlaced;
    189   };
    190 
    191   void AppendAction(const std::string& action) {
    192     if (!actions_.empty())
    193       actions_ += ",";
    194     actions_ += action;
    195   }
    196 
    197   std::map<RRMode, ModeDetails> modes_;
    198 
    199   // Outputs to be returned by GetOutputs().
    200   std::vector<OutputConfigurator::OutputSnapshot> outputs_;
    201 
    202   std::string actions_;
    203 
    204   DISALLOW_COPY_AND_ASSIGN(TestDelegate);
    205 };
    206 
    207 class TestStateController : public OutputConfigurator::StateController {
    208  public:
    209   TestStateController() : state_(STATE_DUAL_EXTENDED) {}
    210   virtual ~TestStateController() {}
    211 
    212   void set_state(OutputState state) { state_ = state; }
    213 
    214   // OutputConfigurator::StateController overrides:
    215   virtual OutputState GetStateForDisplayIds(
    216       const std::vector<int64>& outputs) const OVERRIDE { return state_; }
    217   virtual bool GetResolutionForDisplayId(
    218       int64 display_id,
    219       int *width,
    220       int *height) const OVERRIDE {
    221     return false;
    222   }
    223 
    224  private:
    225   OutputState state_;
    226 
    227   DISALLOW_COPY_AND_ASSIGN(TestStateController);
    228 };
    229 
    230 class TestMirroringController
    231     : public OutputConfigurator::SoftwareMirroringController {
    232  public:
    233   TestMirroringController() : software_mirroring_enabled_(false) {}
    234   virtual ~TestMirroringController() {}
    235 
    236   virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
    237     software_mirroring_enabled_ = enabled;
    238   }
    239 
    240   bool software_mirroring_enabled() const {
    241     return software_mirroring_enabled_;
    242   }
    243 
    244  private:
    245   bool software_mirroring_enabled_;
    246 
    247   DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
    248 };
    249 
    250 class OutputConfiguratorTest : public testing::Test {
    251  public:
    252   OutputConfiguratorTest()
    253       : test_api_(&configurator_, TestDelegate::kXRandREventBase) {}
    254   virtual ~OutputConfiguratorTest() {}
    255 
    256   virtual void SetUp() OVERRIDE {
    257     delegate_ = new TestDelegate();
    258     configurator_.SetDelegateForTesting(
    259         scoped_ptr<OutputConfigurator::Delegate>(delegate_));
    260     configurator_.set_state_controller(&state_controller_);
    261     configurator_.set_mirroring_controller(&mirroring_controller_);
    262 
    263     OutputConfigurator::OutputSnapshot* o = &outputs_[0];
    264     o->output = 1;
    265     o->crtc = 10;
    266     o->current_mode = kSmallModeId;
    267     o->native_mode = kSmallModeId;
    268     o->selected_mode = kSmallModeId;
    269     o->mirror_mode = kSmallModeId;
    270     o->x = 0;
    271     o->y = 0;
    272     o->is_internal = true;
    273     o->is_aspect_preserving_scaling = true;
    274     o->touch_device_id = 0;
    275     o->has_display_id = true;
    276 
    277     o = &outputs_[1];
    278     o->output = 2;
    279     o->crtc = 11;
    280     o->current_mode = kBigModeId;
    281     o->native_mode = kBigModeId;
    282     o->selected_mode = kBigModeId;
    283     o->mirror_mode = kSmallModeId;
    284     o->x = 0;
    285     o->y = 0;
    286     o->is_internal = false;
    287     o->is_aspect_preserving_scaling = true;
    288     o->touch_device_id = 0;
    289     o->has_display_id = true;
    290 
    291     UpdateOutputs(2);
    292     delegate_->AddMode(kSmallModeId, kSmallModeWidth, kSmallModeHeight, false);
    293     delegate_->AddMode(kBigModeId, kBigModeWidth, kBigModeHeight, false);
    294   }
    295 
    296   void DisableNativeMirroring() {
    297     outputs_[0].mirror_mode = outputs_[1].mirror_mode = 0L;
    298   }
    299 
    300  protected:
    301   // Predefined modes that can be used by outputs.
    302   static const int kSmallModeId = 20;
    303   static const int kSmallModeWidth = 1366;
    304   static const int kSmallModeHeight = 768;
    305 
    306   static const int kBigModeId = 21;
    307   static const int kBigModeWidth = 2560;
    308   static const int kBigModeHeight = 1600;
    309 
    310   // Configures |delegate_| to return the first |num_outputs| entries from
    311   // |outputs_|.
    312   virtual void UpdateOutputs(size_t num_outputs) {
    313     ASSERT_LE(num_outputs, arraysize(outputs_));
    314     std::vector<OutputConfigurator::OutputSnapshot> outputs;
    315     for (size_t i = 0; i < num_outputs; ++i)
    316       outputs.push_back(outputs_[i]);
    317     delegate_->set_outputs(outputs);
    318   }
    319 
    320   // Initializes |configurator_| with a single internal display.
    321   virtual void InitWithSingleOutput() {
    322     UpdateOutputs(1);
    323     EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    324     configurator_.Init(false);
    325     EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    326     configurator_.Start(0);
    327     EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
    328                           GetFramebufferAction(kSmallModeWidth,
    329                               kSmallModeHeight, outputs_[0].crtc, 0).c_str(),
    330                           GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    331                                         outputs_[0].output).c_str(),
    332                           kForceDPMS, kUngrab, kProjectingOff, NULL),
    333               delegate_->GetActionsAndClear());
    334   }
    335 
    336   base::MessageLoop message_loop_;
    337   TestStateController state_controller_;
    338   TestMirroringController mirroring_controller_;
    339   OutputConfigurator configurator_;
    340   TestDelegate* delegate_;  // not owned
    341   OutputConfigurator::TestApi test_api_;
    342 
    343   OutputConfigurator::OutputSnapshot outputs_[2];
    344 
    345  private:
    346   DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
    347 };
    348 
    349 }  // namespace
    350 
    351 TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
    352   InitWithSingleOutput();
    353 
    354   // Connect a second output and check that the configurator enters
    355   // extended mode.
    356   UpdateOutputs(2);
    357   const int kDualHeight =
    358       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
    359   state_controller_.set_state(STATE_DUAL_EXTENDED);
    360   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    361   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    362                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    363                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    364                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    365                             outputs_[0].output).c_str(),
    366                         GetCrtcAction(outputs_[1].crtc, 0,
    367                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    368                             kBigModeId, outputs_[1].output).c_str(),
    369                         kUngrab, kProjectingOn, NULL),
    370             delegate_->GetActionsAndClear());
    371   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    372 
    373   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    374   EXPECT_EQ(JoinActions(kGrab,
    375                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    376                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    377                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    378                             outputs_[0].output).c_str(),
    379                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    380                             outputs_[1].output).c_str(),
    381                         kUngrab, NULL),
    382             delegate_->GetActionsAndClear());
    383   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    384 
    385   // Disconnect the second output.
    386   UpdateOutputs(1);
    387   EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
    388   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    389                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    390                             outputs_[0].crtc, 0).c_str(),
    391                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    392                             outputs_[0].output).c_str(),
    393                         kUngrab, kProjectingOff, NULL),
    394             delegate_->GetActionsAndClear());
    395   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    396 
    397   // Software Mirroring
    398   DisableNativeMirroring();
    399   UpdateOutputs(2);
    400   state_controller_.set_state(STATE_DUAL_EXTENDED);
    401   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    402   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    403                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    404                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    405                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    406                             outputs_[0].output).c_str(),
    407                         GetCrtcAction(outputs_[1].crtc, 0,
    408                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    409                             kBigModeId, outputs_[1].output).c_str(),
    410                         kUngrab, kProjectingOn, NULL),
    411             delegate_->GetActionsAndClear());
    412   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    413 
    414   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    415   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
    416             delegate_->GetActionsAndClear());
    417   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    418   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    419 
    420   // Setting STATE_DUAL_MIRROR should try to reconfigure
    421   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    422   EXPECT_EQ(JoinActions(NULL), delegate_->GetActionsAndClear());
    423   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    424 
    425   // Set back to software mirror mode.
    426   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    427   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL),
    428             delegate_->GetActionsAndClear());
    429   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    430   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    431 
    432   // Disconnect the second output.
    433   UpdateOutputs(1);
    434   EXPECT_TRUE(test_api_.SendOutputChangeEvents(false));
    435   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    436                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    437                             outputs_[0].crtc, 0).c_str(),
    438                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    439                             outputs_[0].output).c_str(),
    440                         kUngrab, kProjectingOff, NULL),
    441             delegate_->GetActionsAndClear());
    442   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    443 }
    444 
    445 TEST_F(OutputConfiguratorTest, SetDisplayPower) {
    446   InitWithSingleOutput();
    447 
    448   UpdateOutputs(2);
    449   state_controller_.set_state(STATE_DUAL_MIRROR);
    450   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    451   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    452                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    453                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    454                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    455                             outputs_[0].output).c_str(),
    456                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    457                             outputs_[1].output).c_str(),
    458                         kUngrab, kProjectingOn, NULL),
    459             delegate_->GetActionsAndClear());
    460   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    461 
    462   // Turning off the internal display should switch the external display to
    463   // its native mode.
    464   configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
    465                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    466   EXPECT_EQ(JoinActions(kGrab,
    467                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
    468                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    469                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    470                             outputs_[0].output).c_str(),
    471                         GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
    472                             outputs_[1].output).c_str(),
    473                         kForceDPMS, kUngrab, NULL),
    474             delegate_->GetActionsAndClear());
    475   EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
    476 
    477   // When all displays are turned off, the framebuffer should switch back
    478   // to the mirrored size.
    479   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    480                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    481   EXPECT_EQ(JoinActions(kGrab,
    482                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    483                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    484                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    485                             outputs_[0].output).c_str(),
    486                         GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
    487                             outputs_[1].output).c_str(),
    488                         kUngrab, NULL),
    489             delegate_->GetActionsAndClear());
    490   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
    491   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    492 
    493   // Turn all displays on and check that mirroring is still used.
    494   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
    495                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    496   EXPECT_EQ(JoinActions(kGrab,
    497                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    498                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    499                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    500                             outputs_[0].output).c_str(),
    501                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    502                             outputs_[1].output).c_str(),
    503                         kForceDPMS, kUngrab, NULL),
    504             delegate_->GetActionsAndClear());
    505   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
    506   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    507 
    508   // Software Mirroring
    509   DisableNativeMirroring();
    510   UpdateOutputs(2);
    511 
    512   const int kDualHeight =
    513       kSmallModeHeight + OutputConfigurator::kVerticalGap + kBigModeHeight;
    514 
    515   state_controller_.set_state(STATE_DUAL_MIRROR);
    516   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    517   // Move to extended
    518   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    519                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    520                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    521                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    522                             outputs_[0].output).c_str(),
    523                         GetCrtcAction(outputs_[1].crtc, 0,
    524                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    525                             kBigModeId, outputs_[1].output).c_str(),
    526                         kUngrab, kProjectingOn, NULL),
    527             delegate_->GetActionsAndClear());
    528   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    529   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    530 
    531   // Turning off the internal display should switch the external display to
    532   // its native mode.
    533   configurator_.SetDisplayPower(DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
    534                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    535   EXPECT_EQ(JoinActions(kGrab,
    536                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
    537                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    538                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    539                             outputs_[0].output).c_str(),
    540                         GetCrtcAction(outputs_[1].crtc, 0, 0, kBigModeId,
    541                             outputs_[1].output).c_str(),
    542                         kForceDPMS, kUngrab, NULL),
    543             delegate_->GetActionsAndClear());
    544   EXPECT_EQ(STATE_SINGLE, configurator_.output_state());
    545   EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
    546 
    547   // When all displays are turned off, the framebuffer should switch back
    548   // to the extended + software mirroring.
    549   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    550                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    551   EXPECT_EQ(JoinActions(kGrab,
    552                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    553                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    554                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    555                             outputs_[0].output).c_str(),
    556                         GetCrtcAction(outputs_[1].crtc, 0,
    557                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    558                             0, outputs_[1].output).c_str(),
    559                         kUngrab, NULL),
    560             delegate_->GetActionsAndClear());
    561   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    562   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    563 
    564   // Turn all displays on and check that mirroring is still used.
    565   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
    566                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    567   EXPECT_EQ(JoinActions(kGrab,
    568                         GetFramebufferAction(kBigModeWidth, kDualHeight,
    569                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    570                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    571                             outputs_[0].output).c_str(),
    572                         GetCrtcAction(outputs_[1].crtc, 0,
    573                             kSmallModeHeight + OutputConfigurator::kVerticalGap,
    574                             kBigModeId, outputs_[1].output).c_str(),
    575                         kForceDPMS, kUngrab, NULL),
    576             delegate_->GetActionsAndClear());
    577   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    578   EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
    579 
    580 }
    581 
    582 TEST_F(OutputConfiguratorTest, SuspendAndResume) {
    583   InitWithSingleOutput();
    584 
    585   // No preparation is needed before suspending when the display is already
    586   // on.  The configurator should still reprobe on resume in case a display
    587   // was connected while suspended.
    588   configurator_.SuspendDisplays();
    589   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    590   configurator_.ResumeDisplays();
    591   EXPECT_EQ(JoinActions(kGrab,
    592                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    593                             outputs_[0].crtc, 0).c_str(),
    594                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    595                             outputs_[0].output).c_str(),
    596                         kForceDPMS, kUngrab, NULL),
    597             delegate_->GetActionsAndClear());
    598 
    599   // Now turn the display off before suspending and check that the
    600   // configurator turns it back on and syncs with the server.
    601   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    602                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    603   EXPECT_EQ(JoinActions(kGrab,
    604                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    605                             outputs_[0].crtc, 0).c_str(),
    606                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    607                             outputs_[0].output).c_str(),
    608                         kUngrab, NULL),
    609             delegate_->GetActionsAndClear());
    610 
    611   configurator_.SuspendDisplays();
    612   EXPECT_EQ(JoinActions(kGrab,
    613                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    614                             outputs_[0].crtc, 0).c_str(),
    615                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    616                             outputs_[0].output).c_str(),
    617                         kForceDPMS, kUngrab, kSync, NULL),
    618             delegate_->GetActionsAndClear());
    619 
    620   configurator_.ResumeDisplays();
    621   EXPECT_EQ(JoinActions(kGrab,
    622                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    623                             outputs_[0].crtc, 0).c_str(),
    624                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    625                             outputs_[0].output).c_str(),
    626                         kForceDPMS, kUngrab, NULL),
    627             delegate_->GetActionsAndClear());
    628 
    629   // If a second, external display is connected, the displays shouldn't be
    630   // powered back on before suspending.
    631   UpdateOutputs(2);
    632   state_controller_.set_state(STATE_DUAL_MIRROR);
    633   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    634   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    635                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    636                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    637                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    638                             outputs_[0].output).c_str(),
    639                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    640                             outputs_[1].output).c_str(),
    641                         kUngrab, kProjectingOn, NULL),
    642             delegate_->GetActionsAndClear());
    643 
    644   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    645                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    646   EXPECT_EQ(JoinActions(kGrab,
    647                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    648                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    649                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    650                             outputs_[0].output).c_str(),
    651                         GetCrtcAction(outputs_[1].crtc, 0, 0, 0,
    652                             outputs_[1].output).c_str(),
    653                         kUngrab, NULL),
    654             delegate_->GetActionsAndClear());
    655 
    656   configurator_.SuspendDisplays();
    657   EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
    658             delegate_->GetActionsAndClear());
    659 
    660   // If a display is disconnected while resuming, the configurator should
    661   // pick up the change.
    662   UpdateOutputs(1);
    663   configurator_.ResumeDisplays();
    664   EXPECT_EQ(JoinActions(kGrab,
    665                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    666                             outputs_[0].crtc, 0).c_str(),
    667                         GetCrtcAction(outputs_[0].crtc, 0, 0, 0,
    668                             outputs_[0].output).c_str(),
    669                         kUngrab, NULL),
    670             delegate_->GetActionsAndClear());
    671 }
    672 
    673 TEST_F(OutputConfiguratorTest, Headless) {
    674   UpdateOutputs(0);
    675   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    676   configurator_.Init(false);
    677   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    678   configurator_.Start(0);
    679   EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab,
    680                         kProjectingOff, NULL),
    681             delegate_->GetActionsAndClear());
    682 
    683   // Not much should happen when the display power state is changed while
    684   // no displays are connected.
    685   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_OFF,
    686                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    687   EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), delegate_->GetActionsAndClear());
    688   configurator_.SetDisplayPower(DISPLAY_POWER_ALL_ON,
    689                                 OutputConfigurator::kSetDisplayPowerNoFlags);
    690   EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
    691             delegate_->GetActionsAndClear());
    692 
    693   // Connect an external display and check that it's configured correctly.
    694   outputs_[0].is_internal = false;
    695   outputs_[0].native_mode = kBigModeId;
    696   outputs_[0].selected_mode = kBigModeId;
    697   UpdateOutputs(1);
    698   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    699   EXPECT_EQ(JoinActions(kUpdateXRandR, kGrab,
    700                         GetFramebufferAction(kBigModeWidth, kBigModeHeight,
    701                             outputs_[0].crtc, 0).c_str(),
    702                         GetCrtcAction(outputs_[0].crtc, 0, 0, kBigModeId,
    703                             outputs_[0].output).c_str(),
    704                         kUngrab, kProjectingOff, NULL),
    705             delegate_->GetActionsAndClear());
    706 }
    707 
    708 TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
    709   UpdateOutputs(2);
    710   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    711   configurator_.Init(false);
    712   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    713 
    714   state_controller_.set_state(STATE_DUAL_MIRROR);
    715   configurator_.Start(0);
    716   EXPECT_EQ(JoinActions(kGrab, kInitXRandR,
    717                         GetFramebufferAction(kSmallModeWidth, kSmallModeHeight,
    718                             outputs_[0].crtc, outputs_[1].crtc).c_str(),
    719                         GetCrtcAction(outputs_[0].crtc, 0, 0, kSmallModeId,
    720                             outputs_[0].output).c_str(),
    721                         GetCrtcAction(outputs_[1].crtc, 0, 0, kSmallModeId,
    722                             outputs_[1].output).c_str(),
    723                         kForceDPMS, kUngrab, kProjectingOn, NULL),
    724             delegate_->GetActionsAndClear());
    725 }
    726 
    727 TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
    728   UpdateOutputs(0);
    729   EXPECT_EQ(kNoActions, delegate_->GetActionsAndClear());
    730   configurator_.Init(false);
    731   configurator_.Start(0);
    732   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_HEADLESS));
    733   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
    734   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    735   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    736 
    737   UpdateOutputs(1);
    738   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    739   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
    740   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_SINGLE));
    741   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    742   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    743 
    744   UpdateOutputs(2);
    745   state_controller_.set_state(STATE_DUAL_EXTENDED);
    746   EXPECT_TRUE(test_api_.SendOutputChangeEvents(true));
    747   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_HEADLESS));
    748   EXPECT_FALSE(configurator_.SetDisplayMode(STATE_SINGLE));
    749   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_MIRROR));
    750   EXPECT_TRUE(configurator_.SetDisplayMode(STATE_DUAL_EXTENDED));
    751 }
    752 
    753 TEST_F(OutputConfiguratorTest, GetOutputStateForDisplays) {
    754   outputs_[0].has_display_id = false;
    755   UpdateOutputs(2);
    756 
    757   configurator_.Init(false);
    758   configurator_.Start(0);
    759 
    760   state_controller_.set_state(STATE_DUAL_MIRROR);
    761   test_api_.SendOutputChangeEvents(true);
    762   EXPECT_EQ(STATE_DUAL_EXTENDED, configurator_.output_state());
    763 
    764   outputs_[0].has_display_id = true;
    765   UpdateOutputs(2);
    766   test_api_.SendOutputChangeEvents(true);
    767   EXPECT_EQ(STATE_DUAL_MIRROR, configurator_.output_state());
    768 }
    769 
    770 }  // namespace chromeos
    771