Skip to content

Commit

Permalink
Scale the content of unified desktop to fit the displays with differe…
Browse files Browse the repository at this point in the history
…nt size.

* A user can pick the scale that fits to one of displays.
* scale won't be saved because the scale value changes depending on the display size connected.
* minor cleanup: remove unnecessary code.

BUG=483811
TEST=covered unit tests. manual.

Review URL: https://codereview.chromium.org/1231003002

Cr-Commit-Position: refs/heads/master@{#339380}
  • Loading branch information
mitoshima authored and Commit bot committed Jul 18, 2015
1 parent fd0f075 commit 5337ca9
Show file tree
Hide file tree
Showing 13 changed files with 217 additions and 80 deletions.
4 changes: 1 addition & 3 deletions ash/accelerators/accelerator_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -301,9 +301,7 @@ void HandleScaleReset() {
}

bool CanHandleScaleUI() {
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
int64 display_id = display_manager->GetDisplayIdForUIScaling();
return display_id != gfx::Display::kInvalidDisplayID;
return Shell::GetInstance()->display_manager()->IsDisplayUIScalingEnabled();
}

void HandleScaleUI(bool up) {
Expand Down
77 changes: 46 additions & 31 deletions ash/display/display_manager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -361,10 +361,9 @@ void DisplayManager::SetDisplayRotation(int64 display_id,

bool DisplayManager::SetDisplayUIScale(int64 display_id,
float ui_scale) {
if (!IsDisplayUIScalingEnabled() ||
gfx::Display::InternalDisplayId() != display_id) {
if (GetDisplayIdForUIScaling() != display_id)
return false;
}

bool found = false;
// TODO(mukai): merge this implementation into SetDisplayMode().
DisplayInfoList display_info_list;
Expand Down Expand Up @@ -414,7 +413,7 @@ void DisplayManager::SetDisplayResolution(int64 display_id,

bool DisplayManager::SetDisplayMode(int64 display_id,
const DisplayMode& display_mode) {
if (IsInternalDisplayId(display_id)) {
if (GetDisplayIdForUIScaling() == display_id) {
SetDisplayUIScale(display_id, display_mode.ui_scale);
return false;
}
Expand Down Expand Up @@ -502,7 +501,7 @@ DisplayMode DisplayManager::GetActiveModeForDisplayId(int64 display_id) const {
const DisplayInfo& info = GetDisplayInfo(display_id);
const std::vector<DisplayMode>& display_modes = info.display_modes();

if (IsInternalDisplayId(display_id)) {
if (GetDisplayIdForUIScaling() == display_id) {
for (size_t i = 0; i < display_modes.size(); ++i) {
if (info.configured_ui_scale() == display_modes[i].ui_scale)
return display_modes[i];
Expand Down Expand Up @@ -955,12 +954,9 @@ std::string DisplayManager::GetDisplayNameForId(int64 id) {
}

int64 DisplayManager::GetDisplayIdForUIScaling() const {
// UI Scaling is effective only on internal display.
int64 display_id = gfx::Display::InternalDisplayId();
#if defined(OS_WIN)
display_id = first_display_id();
#endif
return display_id;
// UI Scaling is effective on internal display or on unified desktop.
return IsInUnifiedMode() ? kUnifiedDisplayId
: gfx::Display::InternalDisplayId();
}

void DisplayManager::SetMirrorMode(bool mirror) {
Expand All @@ -975,22 +971,6 @@ void DisplayManager::SetMirrorMode(bool mirror) {
Shell::GetInstance()->display_configurator()->SetDisplayMode(new_state);
return;
}

// This is fallback path to emulate mirroroing on desktop and unit test.
DisplayInfoList display_info_list;
for (DisplayList::const_iterator iter = active_display_list_.begin();
(display_info_list.size() < 2 && iter != active_display_list_.end());
++iter) {
if (iter->id() == kUnifiedDisplayId)
continue;
display_info_list.push_back(GetDisplayInfo(iter->id()));
}
for (auto iter = software_mirroring_display_list_.begin();
(display_info_list.size() < 2 &&
iter != software_mirroring_display_list_.end());
++iter) {
display_info_list.push_back(GetDisplayInfo(iter->id()));
}
multi_display_mode_ = mirror ? MIRRORING : default_multi_display_mode_;
ReconfigureDisplays();
if (Shell::GetInstance()->display_configurator_animation()) {
Expand Down Expand Up @@ -1167,30 +1147,50 @@ void DisplayManager::CreateSoftwareMirroringDisplayInfo(
info.SetOverscanInsets(gfx::Insets());
InsertAndUpdateDisplayInfo(info);
software_mirroring_display_list_.push_back(
CreateDisplayFromDisplayInfoById(mirroring_display_id_));
CreateMirroringDisplayFromDisplayInfoById(mirroring_display_id_,
gfx::Point(), 1.0f));
display_info_list->erase(iter);
break;
}
case UNIFIED: {
// TODO(oshima): Suport displays that have different heights.
// TODO(oshima): Currently, all displays are laid out horizontally,
// from left to right. Allow more flexible layouts, such as
// right to left, or vertical layouts.
gfx::Rect unified_bounds;
software_mirroring_display_list_.clear();

int max_height = std::numeric_limits<int>::min();
for (auto& info : *display_info_list)
max_height = std::max(max_height, info.size_in_pixel().height());

std::vector<DisplayMode> display_mode_list;
std::set<float> ui_scales;

for (auto& info : *display_info_list) {
InsertAndUpdateDisplayInfo(info);
gfx::Display display = CreateDisplayFromDisplayInfoById(info.id());
gfx::Point origin(unified_bounds.right(), 0);
display.set_bounds(gfx::Rect(origin, info.size_in_pixel()));
float ui_scale =
info.size_in_pixel().height() / static_cast<float>(max_height);
// The display is scaled to fit the unified desktop size.
gfx::Display display = CreateMirroringDisplayFromDisplayInfoById(
info.id(), origin, 1.0f / ui_scale);
display.UpdateWorkAreaFromInsets(gfx::Insets());
unified_bounds.Union(display.bounds());

ui_scales.insert(ui_scale);

software_mirroring_display_list_.push_back(display);
}
DisplayInfo info(kUnifiedDisplayId, "Unified Desktop", false);
info.SetBounds(unified_bounds);

DisplayMode native_mode(unified_bounds.size(), 60.0f, false, true);
info.SetDisplayModes(
CreateUnifiedDisplayModeList(native_mode, ui_scales));

display_info_list->clear();
display_info_list->push_back(info);
InsertAndUpdateDisplayInfo(info);
break;
}
case EXTENDED:
Expand Down Expand Up @@ -1259,6 +1259,21 @@ gfx::Display DisplayManager::CreateDisplayFromDisplayInfoById(int64 id) {
return new_display;
}

gfx::Display DisplayManager::CreateMirroringDisplayFromDisplayInfoById(
int64 id,
const gfx::Point& origin,
float scale) {
DCHECK(display_info_.find(id) != display_info_.end()) << "id=" << id;
const DisplayInfo& display_info = display_info_[id];

gfx::Display new_display(display_info.id());
new_display.SetScaleAndBounds(
1.0f, gfx::Rect(origin, gfx::ToFlooredSize(gfx::ScaleSize(
display_info.size_in_pixel(), scale))));
new_display.set_touch_support(display_info.touch_support());
return new_display;
}

bool DisplayManager::UpdateNonPrimaryDisplayBoundsForLayout(
DisplayList* displays,
std::vector<size_t>* updated_indices) const {
Expand Down
8 changes: 8 additions & 0 deletions ash/display/display_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,14 @@ class ASH_EXPORT DisplayManager
// Creates a display object from the DisplayInfo for |display_id|.
gfx::Display CreateDisplayFromDisplayInfoById(int64 display_id);

// Creates a display object from the DisplayInfo for |display_id| for
// mirroring. The size of the display will be scaled using |scale|
// with the offset using |origin|.
gfx::Display CreateMirroringDisplayFromDisplayInfoById(
int64 display_id,
const gfx::Point& origin,
float scale);

// Updates the bounds of all non-primary displays in |display_list| and
// append the indices of displays updated to |updated_indices|.
// When the size of |display_list| equals 2, the bounds are updated using
Expand Down
52 changes: 46 additions & 6 deletions ash/display/display_manager_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,43 @@ TEST_F(DisplayManagerTest, Use125DSFRorUIScaling) {
DisplayInfo::SetUse125DSFForUIScaling(false);
}

TEST_F(DisplayManagerTest, UIScaleInUnifiedMode) {
if (!SupportsMultipleDisplays())
return;

test::DisplayManagerTestApi::EnableUnifiedDesktopForTest();

// Don't check root window destruction in unified mode.
Shell::GetPrimaryRootWindow()->RemoveObserver(this);

DisplayManager* display_manager = Shell::GetInstance()->display_manager();

UpdateDisplay("200x200, 400x400");

int64 unified_id = Shell::GetScreen()->GetPrimaryDisplay().id();
EXPECT_EQ("800x400",
Shell::GetScreen()->GetPrimaryDisplay().size().ToString());
DisplayMode active_mode =
display_manager->GetActiveModeForDisplayId(unified_id);
EXPECT_EQ(1.0f, active_mode.ui_scale);
EXPECT_EQ("800x400", active_mode.size.ToString());

EXPECT_TRUE(display_manager->SetDisplayUIScale(unified_id, 0.5f));
EXPECT_EQ("400x200",
Shell::GetScreen()->GetPrimaryDisplay().size().ToString());
active_mode = display_manager->GetActiveModeForDisplayId(unified_id);
EXPECT_EQ(0.5f, active_mode.ui_scale);
EXPECT_EQ("800x400", active_mode.size.ToString());

// UI scale will not persist in unified desktop mode.
UpdateDisplay("200x200, 600x600");
EXPECT_EQ("1200x600",
Shell::GetScreen()->GetPrimaryDisplay().size().ToString());
active_mode = display_manager->GetActiveModeForDisplayId(unified_id);
EXPECT_EQ(1.0f, active_mode.ui_scale);
EXPECT_EQ("1200x600", active_mode.size.ToString());
}

#if defined(OS_WIN)
// TODO(scottmg): RootWindow doesn't get resized on Windows
// Ash. http://crbug.com/247916.
Expand Down Expand Up @@ -1508,21 +1545,24 @@ TEST_F(DisplayManagerTest, UnifiedDesktopBasic) {
// Defaults to the unified desktop.
gfx::Screen* screen =
gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_ALTERNATE);
EXPECT_EQ("700x500", screen->GetPrimaryDisplay().size().ToString());
// The 1st display is scaled so that it has the same height as 2nd display.
// 300 * 500 / 200 + 400 = 1150.
EXPECT_EQ("1150x500", screen->GetPrimaryDisplay().size().ToString());

display_manager()->SetMirrorMode(true);
EXPECT_EQ("300x200", screen->GetPrimaryDisplay().size().ToString());

display_manager()->SetMirrorMode(false);
EXPECT_EQ("700x500", screen->GetPrimaryDisplay().size().ToString());
EXPECT_EQ("1150x500", screen->GetPrimaryDisplay().size().ToString());

// Switch to single desktop.
UpdateDisplay("500x300");
EXPECT_EQ("500x300", screen->GetPrimaryDisplay().size().ToString());

// Switch to unified desktop.
UpdateDisplay("500x300,400x500");
EXPECT_EQ("900x500", screen->GetPrimaryDisplay().size().ToString());
// 500 * 500 / 300 + 400 ~= 1233.
EXPECT_EQ("1233x500", screen->GetPrimaryDisplay().size().ToString());

// Switch back to extended desktop.
display_manager()->SetDefaultMultiDisplayMode(DisplayManager::EXTENDED);
Expand Down Expand Up @@ -1560,13 +1600,13 @@ TEST_F(DisplayManagerTest, RotateUnifiedDesktop) {
gfx::Screen* screen =
gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_ALTERNATE);
const gfx::Display& display = screen->GetPrimaryDisplay();
EXPECT_EQ("700x500", display.size().ToString());
EXPECT_EQ("1150x500", display.size().ToString());
display_manager()->SetDisplayRotation(display.id(), gfx::Display::ROTATE_90,
gfx::Display::ROTATION_SOURCE_ACTIVE);
EXPECT_EQ("500x700", screen->GetPrimaryDisplay().size().ToString());
EXPECT_EQ("500x1150", screen->GetPrimaryDisplay().size().ToString());
display_manager()->SetDisplayRotation(display.id(), gfx::Display::ROTATE_0,
gfx::Display::ROTATION_SOURCE_ACTIVE);
EXPECT_EQ("700x500", screen->GetPrimaryDisplay().size().ToString());
EXPECT_EQ("1150x500", screen->GetPrimaryDisplay().size().ToString());

UpdateDisplay("300x200");
EXPECT_EQ("300x200", screen->GetPrimaryDisplay().size().ToString());
Expand Down
15 changes: 15 additions & 0 deletions ash/display/display_util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,21 @@ std::vector<DisplayMode> CreateInternalDisplayModeList(
return display_mode_list;
}

std::vector<DisplayMode> CreateUnifiedDisplayModeList(
const DisplayMode& native_mode,
const std::set<float>& scales) {
std::vector<DisplayMode> display_mode_list;

float native_ui_scale = native_mode.device_scale_factor;
for (float ui_scale : scales) {
DisplayMode mode = native_mode;
mode.ui_scale = ui_scale;
mode.native = (ui_scale == native_ui_scale);
display_mode_list.push_back(mode);
}
return display_mode_list;
}

// static
float GetNextUIScale(const DisplayInfo& info, bool up) {
ScaleComparator comparator(info.configured_ui_scale());
Expand Down
7 changes: 7 additions & 0 deletions ash/display/display_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#ifndef ASH_DISPLAY_DISPLAY_UTIL_H_
#define ASH_DISPLAY_DISPLAY_UTIL_H_

#include <set>
#include <vector>

#include "ash/ash_export.h"
Expand All @@ -26,6 +27,12 @@ class DisplayInfo;
ASH_EXPORT std::vector<DisplayMode> CreateInternalDisplayModeList(
const DisplayMode& native_mode);

// Creates the display mode list for unified display
// based on |native_mode| and |scales|.
ASH_EXPORT std::vector<DisplayMode> CreateUnifiedDisplayModeList(
const DisplayMode& native_mode,
const std::set<float>& scales);

// Returns next valid UI scale.
float GetNextUIScale(const DisplayInfo& info, bool up);

Expand Down
8 changes: 2 additions & 6 deletions ash/display/mirror_window_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -163,18 +163,14 @@ void MirrorWindowController::UpdateWindow(

multi_display_mode_ = GetCurrentMultiDisplayMode();

gfx::Point mirroring_origin;
for (const DisplayInfo& display_info : display_info_list) {
scoped_ptr<RootWindowTransformer> transformer;
if (display_manager->IsInMirrorMode()) {
transformer.reset(CreateRootWindowTransformerForMirroredDisplay(
source_display_info, display_info));
} else if (display_manager->IsInUnifiedMode()) {
gfx::Display display;
display.SetScaleAndBounds(
1.0f,
gfx::Rect(mirroring_origin, display_info.bounds_in_native().size()));
mirroring_origin.SetPoint(display.bounds().right(), 0);
gfx::Display display =
display_manager->GetMirroringDisplayById(display_info.id());
transformer.reset(CreateRootWindowTransformerForUnifiedDesktop(
primary.bounds(), display));
} else {
Expand Down
38 changes: 24 additions & 14 deletions ash/display/root_window_transformers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,18 @@ class AshRootWindowTransformer : public RootWindowTransformer {
AshRootWindowTransformer(aura::Window* root,
const gfx::Display& display)
: root_window_(root) {
DisplayInfo info = Shell::GetInstance()->display_manager()->
GetDisplayInfo(display.id());
DisplayManager* display_manager = Shell::GetInstance()->display_manager();
DisplayInfo info = display_manager->GetDisplayInfo(display.id());
host_insets_ = info.GetOverscanInsetsInPixel();
root_window_ui_scale_ = info.GetEffectiveUIScale();
// In unified mode, the scaling happen when mirroring, so don't apply
// scaling to the root window.
const float apply_ui_scale =
display_manager->IsInUnifiedMode() ? 1.0f : root_window_ui_scale_;

root_window_bounds_transform_ =
CreateInsetsAndScaleTransform(host_insets_,
display.device_scale_factor(),
root_window_ui_scale_) *
CreateInsetsAndScaleTransform(
host_insets_, display.device_scale_factor(), apply_ui_scale) *
CreateRotationTransform(root, display);
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAshEnableMirroredScreen)) {
Expand All @@ -173,11 +177,15 @@ class AshRootWindowTransformer : public RootWindowTransformer {
bounds = ui::ConvertRectToDIP(root_window_->layer(), bounds);
gfx::RectF new_bounds(bounds);
root_window_bounds_transform_.TransformRect(&new_bounds);
// Apply |root_window_scale_| twice as the downscaling
// is already applied once in |SetTransformInternal()|.
// TODO(oshima): This is a bit ugly. Consider specifying
// the pseudo host resolution instead.
new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
if (Shell::GetInstance()->display_manager()->IsInUnifiedMode()) {
new_bounds.Scale(root_window_ui_scale_);
} else {
// Apply |root_window_scale_| twice as the downscaling
// is already applied once in |SetTransformInternal()|.
// TODO(oshima): This is a bit ugly. Consider specifying
// the pseudo host resolution instead.
new_bounds.Scale(root_window_ui_scale_ * root_window_ui_scale_);
}
// Ignore the origin because RootWindow's insets are handled by
// the transform.
// Floor the size because the bounds is no longer aligned to
Expand Down Expand Up @@ -279,12 +287,14 @@ class PartialBoundsRootWindowTransformer : public RootWindowTransformer {
public:
PartialBoundsRootWindowTransformer(const gfx::Rect& screen_bounds,
const gfx::Display& display) {
gfx::SizeF root_size(display.bounds().size());
root_size.Scale(display.device_scale_factor());
root_bounds_ = gfx::Rect(gfx::ToFlooredSize(root_size));

DisplayInfo display_info =
Shell::GetInstance()->display_manager()->GetDisplayInfo(display.id());
root_bounds_ = gfx::Rect(display_info.bounds_in_native().size());
transform_.Translate(-SkIntToMScalar(display.bounds().x()),
-SkIntToMScalar(display.bounds().y()));
float scale =
root_bounds_.height() / static_cast<float>(screen_bounds.height());
transform_.Scale(scale, scale);
}

// RootWindowTransformer:
Expand Down
Loading

0 comments on commit 5337ca9

Please sign in to comment.