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