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