This source file includes following definitions.
- DisplaySnapshotToString
- GetBackgroundAction
- GetAddOutputModeAction
- GetCrtcAction
- GetFramebufferAction
- GetCTMAction
- GetSetHDCPStateAction
- JoinActions
- AppendAction
- GetActionsAndClear
- configure_touchscreens_
- GetCTM
- set_configure_touchscreens
- AssociateTouchscreens
- ConfigureCTM
- log_
- outputs
- set_outputs
- set_max_configurable_pixels
- set_hdcp_state
- Initialize
- GrabServer
- UngrabServer
- SyncWithServer
- SetBackgroundColor
- ForceDPMSOn
- GetOutputs
- AddMode
- Configure
- CreateFrameBuffer
- GetHDCPState
- SetHDCPState
- GetAvailableColorCalibrationProfiles
- SetColorCalibrationProfile
- AddObserver
- RemoveObserver
- num_changes
- num_failures
- latest_outputs
- latest_failed_state
- Reset
- OnDisplayModeChanged
- OnDisplayModeChangeFailed
- set_state
- GetStateForDisplayIds
- GetResolutionForDisplayId
- SetSoftwareMirroring
- software_mirroring_enabled
- test_api_
- SetUp
- UpdateOutputs
- InitWithSingleOutput
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
- TEST_F
#include "ui/display/chromeos/output_configurator.h"
#include <stdint.h>
#include <cmath>
#include <cstdarg>
#include <map>
#include <string>
#include <vector>
#include "base/compiler_specific.h"
#include "base/format_macros.h"
#include "base/memory/scoped_vector.h"
#include "base/message_loop/message_loop.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/display/chromeos/display_mode.h"
#include "ui/display/chromeos/native_display_delegate.h"
#include "ui/display/chromeos/test/test_display_snapshot.h"
namespace ui {
namespace {
const char kInitXRandR[] = "init";
const char kGrab[] = "grab";
const char kUngrab[] = "ungrab";
const char kSync[] = "sync";
const char kForceDPMS[] = "dpms";
const char kNoActions[] = "";
std::string DisplaySnapshotToString(const DisplaySnapshot& output) {
return base::StringPrintf("id=%" PRId64, output.display_id());
}
std::string GetBackgroundAction(uint32_t color_argb) {
return base::StringPrintf("background(0x%x)", color_argb);
}
std::string GetAddOutputModeAction(const DisplaySnapshot& output,
const DisplayMode* mode) {
return base::StringPrintf("add_mode(output=%" PRId64 ",mode=%s)",
output.display_id(),
mode->ToString().c_str());
}
std::string GetCrtcAction(const DisplaySnapshot& output,
const DisplayMode* mode,
const gfx::Point& origin) {
return base::StringPrintf("crtc(display=[%s],x=%d,y=%d,mode=[%s])",
DisplaySnapshotToString(output).c_str(),
origin.x(),
origin.y(),
mode ? mode->ToString().c_str() : "NULL");
}
std::string GetFramebufferAction(const gfx::Size& size,
const DisplaySnapshot* out1,
const DisplaySnapshot* out2) {
return base::StringPrintf(
"framebuffer(width=%d,height=%d,display1=%s,display2=%s)",
size.width(),
size.height(),
out1 ? DisplaySnapshotToString(*out1).c_str() : "NULL",
out2 ? DisplaySnapshotToString(*out2).c_str() : "NULL");
}
std::string GetCTMAction(
int device_id,
const OutputConfigurator::CoordinateTransformation& ctm) {
return base::StringPrintf("ctm(id=%d,transform=(%f,%f,%f,%f))",
device_id,
ctm.x_scale,
ctm.x_offset,
ctm.y_scale,
ctm.y_offset);
}
std::string GetSetHDCPStateAction(const DisplaySnapshot& output,
HDCPState state) {
return base::StringPrintf(
"set_hdcp(id=%" PRId64 ",state=%d)", output.display_id(), state);
}
std::string JoinActions(const char* action, ...) {
std::string actions;
va_list arg_list;
va_start(arg_list, action);
while (action) {
if (!actions.empty())
actions += ",";
actions += action;
action = va_arg(arg_list, const char*);
}
va_end(arg_list);
return actions;
}
class ActionLogger {
public:
ActionLogger() {}
void AppendAction(const std::string& action) {
if (!actions_.empty())
actions_ += ",";
actions_ += action;
}
std::string GetActionsAndClear() {
std::string actions = actions_;
actions_.clear();
return actions;
}
private:
std::string actions_;
DISALLOW_COPY_AND_ASSIGN(ActionLogger);
};
class TestTouchscreenDelegate : public OutputConfigurator::TouchscreenDelegate {
public:
explicit TestTouchscreenDelegate(ActionLogger* log)
: log_(log),
configure_touchscreens_(false) {}
virtual ~TestTouchscreenDelegate() {}
const OutputConfigurator::CoordinateTransformation& GetCTM(
int touch_device_id) {
return ctms_[touch_device_id];
}
void set_configure_touchscreens(bool state) {
configure_touchscreens_ = state;
}
virtual void AssociateTouchscreens(
OutputConfigurator::DisplayStateList* outputs) OVERRIDE {
if (configure_touchscreens_) {
for (size_t i = 0; i < outputs->size(); ++i)
(*outputs)[i].touch_device_id = i + 1;
}
}
virtual void ConfigureCTM(
int touch_device_id,
const OutputConfigurator::CoordinateTransformation& ctm) OVERRIDE {
log_->AppendAction(GetCTMAction(touch_device_id, ctm));
ctms_[touch_device_id] = ctm;
}
private:
ActionLogger* log_;
bool configure_touchscreens_;
std::map<int, OutputConfigurator::CoordinateTransformation> ctms_;
DISALLOW_COPY_AND_ASSIGN(TestTouchscreenDelegate);
};
class TestNativeDisplayDelegate : public NativeDisplayDelegate {
public:
explicit TestNativeDisplayDelegate(ActionLogger* log)
: max_configurable_pixels_(0),
hdcp_state_(HDCP_STATE_UNDESIRED),
log_(log) {}
virtual ~TestNativeDisplayDelegate() {}
const std::vector<DisplaySnapshot*>& outputs() const { return outputs_; }
void set_outputs(const std::vector<DisplaySnapshot*>& outputs) {
outputs_ = outputs;
}
void set_max_configurable_pixels(int pixels) {
max_configurable_pixels_ = pixels;
}
void set_hdcp_state(HDCPState state) { hdcp_state_ = state; }
virtual void Initialize() OVERRIDE { log_->AppendAction(kInitXRandR); }
virtual void GrabServer() OVERRIDE { log_->AppendAction(kGrab); }
virtual void UngrabServer() OVERRIDE { log_->AppendAction(kUngrab); }
virtual void SyncWithServer() OVERRIDE { log_->AppendAction(kSync); }
virtual void SetBackgroundColor(uint32_t color_argb) OVERRIDE {
log_->AppendAction(GetBackgroundAction(color_argb));
}
virtual void ForceDPMSOn() OVERRIDE { log_->AppendAction(kForceDPMS); }
virtual std::vector<DisplaySnapshot*> GetOutputs() OVERRIDE {
return outputs_;
}
virtual void AddMode(const DisplaySnapshot& output,
const DisplayMode* mode) OVERRIDE {
log_->AppendAction(GetAddOutputModeAction(output, mode));
}
virtual bool Configure(const DisplaySnapshot& output,
const DisplayMode* mode,
const gfx::Point& origin) OVERRIDE {
log_->AppendAction(GetCrtcAction(output, mode, origin));
if (max_configurable_pixels_ == 0)
return true;
if (!mode)
return false;
return mode->size().GetArea() <= max_configurable_pixels_;
}
virtual void CreateFrameBuffer(const gfx::Size& size) OVERRIDE {
log_->AppendAction(
GetFramebufferAction(size,
outputs_.size() >= 1 ? outputs_[0] : NULL,
outputs_.size() >= 2 ? outputs_[1] : NULL));
}
virtual bool GetHDCPState(const DisplaySnapshot& output,
HDCPState* state) OVERRIDE {
*state = hdcp_state_;
return true;
}
virtual bool SetHDCPState(const DisplaySnapshot& output,
HDCPState state) OVERRIDE {
log_->AppendAction(GetSetHDCPStateAction(output, state));
return true;
}
virtual std::vector<ui::ColorCalibrationProfile>
GetAvailableColorCalibrationProfiles(
const DisplaySnapshot& output) OVERRIDE {
return std::vector<ui::ColorCalibrationProfile>();
}
virtual bool SetColorCalibrationProfile(
const DisplaySnapshot& output,
ui::ColorCalibrationProfile new_profile) OVERRIDE {
return false;
}
virtual void AddObserver(NativeDisplayObserver* observer) OVERRIDE {}
virtual void RemoveObserver(NativeDisplayObserver* observer) OVERRIDE {}
private:
std::vector<DisplaySnapshot*> outputs_;
int max_configurable_pixels_;
HDCPState hdcp_state_;
ActionLogger* log_;
DISALLOW_COPY_AND_ASSIGN(TestNativeDisplayDelegate);
};
class TestObserver : public OutputConfigurator::Observer {
public:
explicit TestObserver(OutputConfigurator* configurator)
: configurator_(configurator) {
Reset();
configurator_->AddObserver(this);
}
virtual ~TestObserver() { configurator_->RemoveObserver(this); }
int num_changes() const { return num_changes_; }
int num_failures() const { return num_failures_; }
const OutputConfigurator::DisplayStateList& latest_outputs() const {
return latest_outputs_;
}
OutputState latest_failed_state() const { return latest_failed_state_; }
void Reset() {
num_changes_ = 0;
num_failures_ = 0;
latest_outputs_.clear();
latest_failed_state_ = OUTPUT_STATE_INVALID;
}
virtual void OnDisplayModeChanged(
const OutputConfigurator::DisplayStateList& outputs) OVERRIDE {
num_changes_++;
latest_outputs_ = outputs;
}
virtual void OnDisplayModeChangeFailed(OutputState failed_new_state)
OVERRIDE {
num_failures_++;
latest_failed_state_ = failed_new_state;
}
private:
OutputConfigurator* configurator_;
int num_changes_;
int num_failures_;
OutputConfigurator::DisplayStateList latest_outputs_;
OutputState latest_failed_state_;
DISALLOW_COPY_AND_ASSIGN(TestObserver);
};
class TestStateController : public OutputConfigurator::StateController {
public:
TestStateController() : state_(OUTPUT_STATE_DUAL_EXTENDED) {}
virtual ~TestStateController() {}
void set_state(OutputState state) { state_ = state; }
virtual OutputState GetStateForDisplayIds(
const std::vector<int64_t>& outputs) const OVERRIDE {
return state_;
}
virtual bool GetResolutionForDisplayId(int64_t display_id,
gfx::Size* size) const OVERRIDE {
return false;
}
private:
OutputState state_;
DISALLOW_COPY_AND_ASSIGN(TestStateController);
};
class TestMirroringController
: public OutputConfigurator::SoftwareMirroringController {
public:
TestMirroringController() : software_mirroring_enabled_(false) {}
virtual ~TestMirroringController() {}
virtual void SetSoftwareMirroring(bool enabled) OVERRIDE {
software_mirroring_enabled_ = enabled;
}
bool software_mirroring_enabled() const {
return software_mirroring_enabled_;
}
private:
bool software_mirroring_enabled_;
DISALLOW_COPY_AND_ASSIGN(TestMirroringController);
};
class OutputConfiguratorTest : public testing::Test {
public:
OutputConfiguratorTest()
: small_mode_(gfx::Size(1366, 768), false, 60.0f),
big_mode_(gfx::Size(2560, 1600), false, 60.0f),
observer_(&configurator_),
test_api_(&configurator_) {}
virtual ~OutputConfiguratorTest() {}
virtual void SetUp() OVERRIDE {
log_.reset(new ActionLogger());
native_display_delegate_ = new TestNativeDisplayDelegate(log_.get());
configurator_.SetNativeDisplayDelegateForTesting(
scoped_ptr<NativeDisplayDelegate>(native_display_delegate_));
touchscreen_delegate_ = new TestTouchscreenDelegate(log_.get());
configurator_.SetTouchscreenDelegateForTesting(
scoped_ptr<OutputConfigurator::TouchscreenDelegate>(
touchscreen_delegate_));
configurator_.set_state_controller(&state_controller_);
configurator_.set_mirroring_controller(&mirroring_controller_);
std::vector<const DisplayMode*> modes;
modes.push_back(&small_mode_);
TestDisplaySnapshot* o = &outputs_[0];
o->set_current_mode(&small_mode_);
o->set_native_mode(&small_mode_);
o->set_modes(modes);
o->set_type(OUTPUT_TYPE_INTERNAL);
o->set_is_aspect_preserving_scaling(true);
o->set_display_id(123);
o->set_has_proper_display_id(true);
o = &outputs_[1];
o->set_current_mode(&big_mode_);
o->set_native_mode(&big_mode_);
modes.push_back(&big_mode_);
o->set_modes(modes);
o->set_type(OUTPUT_TYPE_HDMI);
o->set_is_aspect_preserving_scaling(true);
o->set_display_id(456);
o->set_has_proper_display_id(true);
UpdateOutputs(2, false);
}
const DisplayMode small_mode_;
const DisplayMode big_mode_;
protected:
void UpdateOutputs(size_t num_outputs, bool send_events) {
ASSERT_LE(num_outputs, arraysize(outputs_));
std::vector<DisplaySnapshot*> outputs;
for (size_t i = 0; i < num_outputs; ++i)
outputs.push_back(&outputs_[i]);
native_display_delegate_->set_outputs(outputs);
if (send_events) {
configurator_.OnConfigurationChanged();
test_api_.TriggerConfigureTimeout();
}
}
void InitWithSingleOutput() {
UpdateOutputs(1, false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.Init(false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.ForceInitialConfigure(0);
EXPECT_EQ(
JoinActions(
kGrab,
kInitXRandR,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL)
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
}
base::MessageLoop message_loop_;
TestStateController state_controller_;
TestMirroringController mirroring_controller_;
OutputConfigurator configurator_;
TestObserver observer_;
scoped_ptr<ActionLogger> log_;
TestNativeDisplayDelegate* native_display_delegate_;
TestTouchscreenDelegate* touchscreen_delegate_;
OutputConfigurator::TestApi test_api_;
TestDisplaySnapshot outputs_[2];
private:
DISALLOW_COPY_AND_ASSIGN(OutputConfiguratorTest);
};
}
TEST_F(OutputConfiguratorTest, FindDisplayModeMatchingSize) {
ScopedVector<const DisplayMode> modes;
modes.push_back(new DisplayMode(gfx::Size(1920, 1200), false, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 30.0));
modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 50.0));
modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 40.0));
modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 0.0));
modes.push_back(new DisplayMode(gfx::Size(1280, 720), true, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1280, 720), false, 40.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 768), true, 0.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 768), true, 40.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 768), true, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 600), true, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 600), false, 40.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 600), false, 50.0));
modes.push_back(new DisplayMode(gfx::Size(640, 480), true, 60.0));
modes.push_back(new DisplayMode(gfx::Size(320, 200), false, 0.0));
TestDisplaySnapshot output;
output.set_modes(modes.get());
EXPECT_EQ(modes[0],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(1920, 1200)));
EXPECT_EQ(modes[2],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(1920, 1080)));
EXPECT_EQ(modes[6],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(1280, 720)));
EXPECT_EQ(modes[9],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(1024, 768)));
EXPECT_EQ(modes[12],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(1024, 600)));
EXPECT_EQ(modes[13],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(640, 480)));
EXPECT_EQ(modes[14],
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(320, 200)));
EXPECT_EQ(NULL,
OutputConfigurator::FindDisplayModeMatchingSize(
output, gfx::Size(1440, 900)));
}
TEST_F(OutputConfiguratorTest, ConnectSecondOutput) {
InitWithSingleOutput();
observer_.Reset();
state_controller_.set_state(OUTPUT_STATE_DUAL_EXTENDED);
UpdateOutputs(2, true);
const int kDualHeight = small_mode_.size().height() +
OutputConfigurator::kVerticalGap +
big_mode_.size().height();
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
&outputs_[0],
&outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1],
&big_mode_,
gfx::Point(0,
small_mode_.size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_MIRROR));
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
UpdateOutputs(1, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
outputs_[1].set_modes(std::vector<const DisplayMode*>(1, &big_mode_));
state_controller_.set_state(OUTPUT_STATE_DUAL_EXTENDED);
UpdateOutputs(2, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
&outputs_[0],
&outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1],
&big_mode_,
gfx::Point(0,
small_mode_.size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
observer_.Reset();
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_MIRROR));
EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_EXTENDED, configurator_.output_state());
EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_EXTENDED));
EXPECT_EQ(JoinActions(NULL), log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_MIRROR));
EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_EXTENDED, configurator_.output_state());
EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
UpdateOutputs(1, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
}
TEST_F(OutputConfiguratorTest, SetDisplayPower) {
InitWithSingleOutput();
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
observer_.Reset();
UpdateOutputs(2, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
configurator_.SetDisplayPower(
chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(big_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_SINGLE, configurator_.output_state());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(kGrab,
GetFramebufferAction(
small_mode_.size(), &outputs_[0], &outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], NULL, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_MIRROR, configurator_.output_state());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_MIRROR, configurator_.output_state());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
outputs_[1].set_modes(std::vector<const DisplayMode*>(1, &big_mode_));
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
observer_.Reset();
UpdateOutputs(2, true);
const int kDualHeight = small_mode_.size().height() +
OutputConfigurator::kVerticalGap +
big_mode_.size().height();
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
&outputs_[0],
&outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1],
&big_mode_,
gfx::Point(0,
small_mode_.size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_EXTENDED, configurator_.output_state());
EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
configurator_.SetDisplayPower(
chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(big_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &big_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_SINGLE, configurator_.output_state());
EXPECT_FALSE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
&outputs_[0],
&outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1],
NULL,
gfx::Point(0,
small_mode_.size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_EXTENDED, configurator_.output_state());
EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
observer_.Reset();
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(gfx::Size(big_mode_.size().width(), kDualHeight),
&outputs_[0],
&outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1],
&big_mode_,
gfx::Point(0,
small_mode_.size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
EXPECT_EQ(OUTPUT_STATE_DUAL_EXTENDED, configurator_.output_state());
EXPECT_TRUE(mirroring_controller_.software_mirroring_enabled());
EXPECT_EQ(1, observer_.num_changes());
}
TEST_F(OutputConfiguratorTest, SuspendAndResume) {
InitWithSingleOutput();
configurator_.SuspendDisplays();
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.ResumeDisplays();
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
configurator_.SuspendDisplays();
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
kSync,
NULL),
log_->GetActionsAndClear());
configurator_.ResumeDisplays();
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
UpdateOutputs(2, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(
JoinActions(kGrab,
GetFramebufferAction(
small_mode_.size(), &outputs_[0], &outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], NULL, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
configurator_.SuspendDisplays();
EXPECT_EQ(JoinActions(kGrab, kUngrab, kSync, NULL),
log_->GetActionsAndClear());
UpdateOutputs(1, false);
configurator_.ResumeDisplays();
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(small_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], NULL, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
}
TEST_F(OutputConfiguratorTest, Headless) {
UpdateOutputs(0, false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.Init(false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.ForceInitialConfigure(0);
EXPECT_EQ(JoinActions(kGrab, kInitXRandR, kForceDPMS, kUngrab, NULL),
log_->GetActionsAndClear());
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_OFF,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(JoinActions(kGrab, kUngrab, NULL), log_->GetActionsAndClear());
configurator_.SetDisplayPower(chromeos::DISPLAY_POWER_ALL_ON,
OutputConfigurator::kSetDisplayPowerNoFlags);
EXPECT_EQ(JoinActions(kGrab, kForceDPMS, kUngrab, NULL),
log_->GetActionsAndClear());
outputs_[0].set_current_mode(outputs_[1].current_mode());
outputs_[0].set_native_mode(outputs_[1].native_mode());
outputs_[0].set_modes(outputs_[1].modes());
outputs_[0].set_type(outputs_[1].type());
UpdateOutputs(1, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(big_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], &big_mode_, gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
}
TEST_F(OutputConfiguratorTest, StartWithTwoOutputs) {
UpdateOutputs(2, false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.Init(false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
configurator_.ForceInitialConfigure(0);
EXPECT_EQ(
JoinActions(
kGrab,
kInitXRandR,
GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
}
TEST_F(OutputConfiguratorTest, InvalidOutputStates) {
UpdateOutputs(0, false);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.Init(false);
configurator_.ForceInitialConfigure(0);
observer_.Reset();
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_HEADLESS));
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_SINGLE));
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_MIRROR));
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_EXTENDED));
EXPECT_EQ(1, observer_.num_changes());
EXPECT_EQ(3, observer_.num_failures());
UpdateOutputs(1, true);
observer_.Reset();
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_HEADLESS));
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_SINGLE));
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_MIRROR));
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_EXTENDED));
EXPECT_EQ(1, observer_.num_changes());
EXPECT_EQ(3, observer_.num_failures());
state_controller_.set_state(OUTPUT_STATE_DUAL_EXTENDED);
UpdateOutputs(2, true);
observer_.Reset();
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_HEADLESS));
EXPECT_FALSE(configurator_.SetDisplayMode(OUTPUT_STATE_SINGLE));
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_MIRROR));
EXPECT_TRUE(configurator_.SetDisplayMode(OUTPUT_STATE_DUAL_EXTENDED));
EXPECT_EQ(2, observer_.num_changes());
EXPECT_EQ(2, observer_.num_failures());
}
TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithoutId) {
outputs_[0].set_has_proper_display_id(false);
UpdateOutputs(2, false);
configurator_.Init(false);
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
configurator_.ForceInitialConfigure(0);
EXPECT_EQ(OUTPUT_STATE_DUAL_EXTENDED, configurator_.output_state());
}
TEST_F(OutputConfiguratorTest, GetOutputStateForDisplaysWithId) {
outputs_[0].set_has_proper_display_id(true);
UpdateOutputs(2, false);
configurator_.Init(false);
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
configurator_.ForceInitialConfigure(0);
EXPECT_EQ(OUTPUT_STATE_DUAL_MIRROR, configurator_.output_state());
}
TEST_F(OutputConfiguratorTest, UpdateCachedOutputsEvenAfterFailure) {
InitWithSingleOutput();
const OutputConfigurator::DisplayStateList* cached =
&configurator_.cached_outputs();
ASSERT_EQ(static_cast<size_t>(1), cached->size());
EXPECT_EQ(outputs_[0].current_mode(), (*cached)[0].display->current_mode());
state_controller_.set_state(OUTPUT_STATE_SINGLE);
UpdateOutputs(2, true);
cached = &configurator_.cached_outputs();
ASSERT_EQ(static_cast<size_t>(2), cached->size());
EXPECT_EQ(outputs_[0].current_mode(), (*cached)[0].display->current_mode());
EXPECT_EQ(outputs_[1].current_mode(), (*cached)[1].display->current_mode());
}
TEST_F(OutputConfiguratorTest, PanelFitting) {
outputs_[0].set_current_mode(&big_mode_);
outputs_[0].set_native_mode(&big_mode_);
outputs_[0].set_modes(std::vector<const DisplayMode*>(1, &big_mode_));
outputs_[1].set_current_mode(&small_mode_);
outputs_[1].set_native_mode(&small_mode_);
outputs_[1].set_modes(std::vector<const DisplayMode*>(1, &small_mode_));
UpdateOutputs(2, false);
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
configurator_.Init(true );
configurator_.ForceInitialConfigure(0);
EXPECT_EQ(OUTPUT_STATE_DUAL_MIRROR, configurator_.output_state());
EXPECT_EQ(
JoinActions(
kGrab,
kInitXRandR,
GetAddOutputModeAction(outputs_[0], &small_mode_).c_str(),
GetFramebufferAction(small_mode_.size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], &small_mode_, gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], &small_mode_, gfx::Point(0, 0)).c_str(),
kForceDPMS,
kUngrab,
NULL),
log_->GetActionsAndClear());
ASSERT_EQ(1, observer_.num_changes());
ASSERT_EQ(static_cast<size_t>(2), observer_.latest_outputs().size());
EXPECT_EQ(&small_mode_, observer_.latest_outputs()[0].mirror_mode);
EXPECT_EQ(&small_mode_,
observer_.latest_outputs()[0].display->current_mode());
EXPECT_EQ(&small_mode_, observer_.latest_outputs()[1].mirror_mode);
EXPECT_EQ(&small_mode_,
observer_.latest_outputs()[1].display->current_mode());
const OutputConfigurator::DisplayState& state = observer_.latest_outputs()[0];
ASSERT_NE(state.display->modes().end(),
std::find(state.display->modes().begin(),
state.display->modes().end(),
&small_mode_));
}
TEST_F(OutputConfiguratorTest, OutputProtection) {
configurator_.Init(false);
configurator_.ForceInitialConfigure(0);
EXPECT_NE(kNoActions, log_->GetActionsAndClear());
OutputConfigurator::OutputProtectionClientId id =
configurator_.RegisterOutputProtectionClient();
EXPECT_NE(0u, id);
UpdateOutputs(1, true);
EXPECT_NE(kNoActions, log_->GetActionsAndClear());
uint32_t link_mask = 0;
uint32_t protection_mask = 0;
EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(
id, outputs_[0].display_id(), &link_mask, &protection_mask));
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_INTERNAL), link_mask);
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
protection_mask);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
UpdateOutputs(2, true);
EXPECT_NE(kNoActions, log_->GetActionsAndClear());
EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(
id, outputs_[1].display_id(), &link_mask, &protection_mask));
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_NONE),
protection_mask);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
EXPECT_TRUE(configurator_.EnableOutputProtection(
id, outputs_[1].display_id(), OUTPUT_PROTECTION_METHOD_HDCP));
EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_DESIRED),
log_->GetActionsAndClear());
native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(
id, outputs_[1].display_id(), &link_mask, &protection_mask));
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_PROTECTION_METHOD_HDCP),
protection_mask);
EXPECT_EQ(kNoActions, log_->GetActionsAndClear());
configurator_.UnregisterOutputProtectionClient(id);
EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_UNDESIRED),
log_->GetActionsAndClear());
}
TEST_F(OutputConfiguratorTest, OutputProtectionTwoClients) {
OutputConfigurator::OutputProtectionClientId client1 =
configurator_.RegisterOutputProtectionClient();
OutputConfigurator::OutputProtectionClientId client2 =
configurator_.RegisterOutputProtectionClient();
EXPECT_NE(client1, client2);
configurator_.Init(false);
configurator_.ForceInitialConfigure(0);
UpdateOutputs(2, true);
EXPECT_NE(kNoActions, log_->GetActionsAndClear());
EXPECT_TRUE(configurator_.EnableOutputProtection(
client1, outputs_[1].display_id(), OUTPUT_PROTECTION_METHOD_HDCP));
EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_DESIRED).c_str(),
log_->GetActionsAndClear());
native_display_delegate_->set_hdcp_state(HDCP_STATE_ENABLED);
uint32_t link_mask = 0;
uint32_t protection_mask = 0;
EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(
client1, outputs_[1].display_id(), &link_mask, &protection_mask));
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
EXPECT_EQ(OUTPUT_PROTECTION_METHOD_HDCP, protection_mask);
EXPECT_TRUE(configurator_.QueryOutputProtectionStatus(
client2, outputs_[1].display_id(), &link_mask, &protection_mask));
EXPECT_EQ(static_cast<uint32_t>(OUTPUT_TYPE_HDMI), link_mask);
EXPECT_EQ(OUTPUT_PROTECTION_METHOD_NONE, protection_mask);
EXPECT_TRUE(configurator_.EnableOutputProtection(
client2, outputs_[1].display_id(), OUTPUT_PROTECTION_METHOD_NONE));
EXPECT_EQ(GetSetHDCPStateAction(outputs_[1], HDCP_STATE_DESIRED).c_str(),
log_->GetActionsAndClear());
EXPECT_TRUE(configurator_.EnableOutputProtection(
client1, outputs_[1].display_id(), OUTPUT_PROTECTION_METHOD_NONE));
EXPECT_EQ(
GetSetHDCPStateAction(outputs_[1], HDCP_STATE_UNDESIRED).c_str(),
log_->GetActionsAndClear());
}
TEST_F(OutputConfiguratorTest, CTMForMultiScreens) {
touchscreen_delegate_->set_configure_touchscreens(true);
UpdateOutputs(2, false);
configurator_.Init(false);
state_controller_.set_state(OUTPUT_STATE_DUAL_EXTENDED);
configurator_.ForceInitialConfigure(0);
const int kDualHeight = small_mode_.size().height() +
OutputConfigurator::kVerticalGap +
big_mode_.size().height();
const int kDualWidth = big_mode_.size().width();
OutputConfigurator::CoordinateTransformation ctm1 =
touchscreen_delegate_->GetCTM(1);
OutputConfigurator::CoordinateTransformation ctm2 =
touchscreen_delegate_->GetCTM(2);
EXPECT_EQ(small_mode_.size().height() - 1,
round((kDualHeight - 1) * ctm1.y_scale));
EXPECT_EQ(0, round((kDualHeight - 1) * ctm1.y_offset));
EXPECT_EQ(big_mode_.size().height() - 1,
round((kDualHeight - 1) * ctm2.y_scale));
EXPECT_EQ(small_mode_.size().height() + OutputConfigurator::kVerticalGap,
round((kDualHeight - 1) * ctm2.y_offset));
EXPECT_EQ(small_mode_.size().width() - 1,
round((kDualWidth - 1) * ctm1.x_scale));
EXPECT_EQ(0, round((kDualWidth - 1) * ctm1.x_offset));
EXPECT_EQ(big_mode_.size().width() - 1,
round((kDualWidth - 1) * ctm2.x_scale));
EXPECT_EQ(0, round((kDualWidth - 1) * ctm2.x_offset));
}
TEST_F(OutputConfiguratorTest, HandleConfigureCrtcFailure) {
InitWithSingleOutput();
ScopedVector<const DisplayMode> modes;
modes.push_back(new DisplayMode(gfx::Size(2560, 1600), false, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1024, 768), false, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1280, 720), false, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 60.0));
modes.push_back(new DisplayMode(gfx::Size(1920, 1080), false, 40.0));
for (unsigned int i = 0; i < arraysize(outputs_); i++) {
outputs_[i].set_modes(modes.get());
outputs_[i].set_current_mode(modes[0]);
outputs_[i].set_native_mode(modes[0]);
}
configurator_.Init(false);
native_display_delegate_->set_max_configurable_pixels(
modes[2]->size().GetArea());
state_controller_.set_state(OUTPUT_STATE_SINGLE);
UpdateOutputs(1, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(big_mode_.size(), &outputs_[0], NULL).c_str(),
GetCrtcAction(outputs_[0], modes[0], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[0], modes[3], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[0], modes[2], gfx::Point(0, 0)).c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
native_display_delegate_->set_max_configurable_pixels(
modes[3]->size().GetArea());
state_controller_.set_state(OUTPUT_STATE_DUAL_MIRROR);
UpdateOutputs(2, true);
EXPECT_EQ(
JoinActions(
kGrab,
GetFramebufferAction(modes[0]->size(), &outputs_[0], &outputs_[1])
.c_str(),
GetCrtcAction(outputs_[0], modes[0], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[0], modes[3], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], modes[0], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1], modes[3], gfx::Point(0, 0)).c_str(),
GetFramebufferAction(
gfx::Size(modes[0]->size().width(),
modes[0]->size().height() + modes[0]->size().height() +
OutputConfigurator::kVerticalGap),
&outputs_[0],
&outputs_[1]).c_str(),
GetCrtcAction(outputs_[0], modes[0], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[0], modes[3], gfx::Point(0, 0)).c_str(),
GetCrtcAction(outputs_[1],
modes[0],
gfx::Point(0,
modes[0]->size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
GetCrtcAction(outputs_[1],
modes[3],
gfx::Point(0,
modes[0]->size().height() +
OutputConfigurator::kVerticalGap))
.c_str(),
kUngrab,
NULL),
log_->GetActionsAndClear());
}
}