| Index: ash/display/display_controller.cc | 
| diff --git a/ash/display/display_controller.cc b/ash/display/display_controller.cc | 
| index 8e3c696c9b9fcada01ca56752413ca59c6f6ca90..995200a6d820ef6d8ca4bfaf506820648ef7466a 100644 | 
| --- a/ash/display/display_controller.cc | 
| +++ b/ash/display/display_controller.cc | 
| @@ -23,6 +23,7 @@ | 
| #include "ui/aura/env.h" | 
| #include "ui/aura/root_window.h" | 
| #include "ui/aura/window.h" | 
| +#include "ui/aura/window_property.h" | 
| #include "ui/compositor/dip_util.h" | 
| #include "ui/gfx/display.h" | 
| #include "ui/gfx/screen.h" | 
| @@ -36,10 +37,14 @@ | 
| #include "ui/base/x/x11_util.h" | 
| #endif  // defined(OS_CHROMEOS) | 
|  | 
| +DECLARE_WINDOW_PROPERTY_TYPE(ash::internal::DisplayInfo::Rotation); | 
|  | 
| namespace ash { | 
| namespace { | 
|  | 
| +DEFINE_WINDOW_PROPERTY_KEY(internal::DisplayInfo::Rotation, kRotationKey, | 
| +                           internal::DisplayInfo::Rotate0); | 
| + | 
| // Primary display stored in global object as it can be | 
| // accessed after Shell is deleted. A separate display instance is created | 
| // during the shutdown instead of always keeping two display instances | 
| @@ -105,6 +110,33 @@ internal::DisplayManager* GetDisplayManager() { | 
| return Shell::GetInstance()->display_manager(); | 
| } | 
|  | 
| +void RotateRootWindow(aura::RootWindow* root_window, | 
| +                      const gfx::Display& display, | 
| +                      const internal::DisplayInfo& info) { | 
| +  // TODO(oshima): Add animation. (crossfade+rotation, or just cross-fade) | 
| +  if (info.rotation() == root_window->GetProperty(kRotationKey)) | 
| +    return; | 
| +  root_window->SetProperty(kRotationKey, info.rotation()); | 
| +  gfx::Transform rotate; | 
| +  switch (info.rotation()) { | 
| +    case internal::DisplayInfo::Rotate0: | 
| +      break; | 
| +    case internal::DisplayInfo::Rotate90: | 
| +      rotate.Translate(display.bounds().height(), 0); | 
| +      rotate.Rotate(90); | 
| +      break; | 
| +    case internal::DisplayInfo::Rotate270: | 
| +      rotate.Translate(0, display.bounds().width()); | 
| +      rotate.Rotate(270); | 
| +      break; | 
| +    case internal::DisplayInfo::Rotate180: | 
| +      rotate.Translate(display.bounds().width(), display.bounds().height()); | 
| +      rotate.Rotate(180); | 
| +      break; | 
| +  } | 
| +  root_window->SetTransform(rotate); | 
| +} | 
| + | 
| void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, | 
| const gfx::Display& display) { | 
| #if defined(OS_CHROMEOS) | 
| @@ -137,6 +169,7 @@ void SetDisplayPropertiesOnHostWindow(aura::RootWindow* root, | 
| kCARDINAL, | 
| 100 * display.device_scale_factor()); | 
| #endif | 
| +  RotateRootWindow(root, display, GetDisplayManager()->GetDisplayInfo(display)); | 
| } | 
|  | 
| }  // namespace | 
| @@ -237,12 +270,29 @@ bool DisplayController::DisplayChangeLimiter::IsThrottled() const { | 
| DisplayController::DisplayController() | 
| : desired_primary_display_id_(gfx::Display::kInvalidDisplayID), | 
| primary_root_window_for_replace_(NULL) { | 
| -#if defined(OS_CHROMEOS) | 
| CommandLine* command_line = CommandLine::ForCurrentProcess(); | 
| +#if defined(OS_CHROMEOS) | 
| if (!command_line->HasSwitch(switches::kAshDisableDisplayChangeLimiter) && | 
| base::chromeos::IsRunningOnChromeOS()) | 
| limiter_.reset(new DisplayChangeLimiter); | 
| #endif | 
| +  if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) { | 
| +    std::string value = command_line->GetSwitchValueASCII( | 
| +        switches::kAshSecondaryDisplayLayout); | 
| +    char layout; | 
| +    int offset = 0; | 
| +    if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) { | 
| +      if (layout == 't') | 
| +        default_display_layout_.position = DisplayLayout::TOP; | 
| +      else if (layout == 'b') | 
| +        default_display_layout_.position = DisplayLayout::BOTTOM; | 
| +      else if (layout == 'r') | 
| +        default_display_layout_.position = DisplayLayout::RIGHT; | 
| +      else if (layout == 'l') | 
| +        default_display_layout_.position = DisplayLayout::LEFT; | 
| +      default_display_layout_.offset = offset; | 
| +    } | 
| +  } | 
| // Reset primary display to make sure that tests don't use | 
| // stale display info from previous tests. | 
| primary_display_id = gfx::Display::kInvalidDisplayID; | 
| @@ -312,24 +362,6 @@ void DisplayController::InitSecondaryDisplays() { | 
| Shell::GetInstance()->InitRootWindowForSecondaryDisplay(root); | 
| } | 
| } | 
| -  CommandLine* command_line = CommandLine::ForCurrentProcess(); | 
| -  if (command_line->HasSwitch(switches::kAshSecondaryDisplayLayout)) { | 
| -    std::string value = command_line->GetSwitchValueASCII( | 
| -        switches::kAshSecondaryDisplayLayout); | 
| -    char layout; | 
| -    int offset; | 
| -    if (sscanf(value.c_str(), "%c,%d", &layout, &offset) == 2) { | 
| -      if (layout == 't') | 
| -        default_display_layout_.position = DisplayLayout::TOP; | 
| -      else if (layout == 'b') | 
| -        default_display_layout_.position = DisplayLayout::BOTTOM; | 
| -      else if (layout == 'r') | 
| -        default_display_layout_.position = DisplayLayout::RIGHT; | 
| -      else if (layout == 'l') | 
| -        default_display_layout_.position = DisplayLayout::LEFT; | 
| -      default_display_layout_.offset = offset; | 
| -    } | 
| -  } | 
| UpdateDisplayBoundsForLayout(); | 
| } | 
|  | 
| @@ -608,15 +640,16 @@ gfx::Display* DisplayController::GetSecondaryDisplay() { | 
| void DisplayController::OnDisplayBoundsChanged(const gfx::Display& display) { | 
| if (limiter_.get()) | 
| limiter_->SetThrottleTimeout(kAfterDisplayChangeThrottleTimeoutMs); | 
| -  DCHECK(!GetDisplayManager()->GetDisplayInfo(display). | 
| -         bounds_in_pixel().IsEmpty()); | 
| +  const internal::DisplayInfo& display_info = | 
| +      GetDisplayManager()->GetDisplayInfo(display); | 
| +  DCHECK(!display_info.bounds_in_pixel().IsEmpty()); | 
|  | 
| NotifyDisplayConfigurationChanging(); | 
| UpdateDisplayBoundsForLayout(); | 
| aura::RootWindow* root = root_windows_[display.id()]; | 
| +  root->SetHostBoundsAndInsets(display_info.bounds_in_pixel(), | 
| +                               display_info.GetOverscanInsetsInPixel()); | 
| SetDisplayPropertiesOnHostWindow(root, display); | 
| -  root->SetHostBounds( | 
| -      GetDisplayManager()->GetDisplayInfo(display).bounds_in_pixel()); | 
| } | 
|  | 
| void DisplayController::OnDisplayAdded(const gfx::Display& display) { | 
| @@ -632,8 +665,11 @@ void DisplayController::OnDisplayAdded(const gfx::Display& display) { | 
| internal::kDisplayIdKey, display.id()); | 
| primary_root_window_for_replace_ = NULL; | 
| UpdateDisplayBoundsForLayout(); | 
| -    root_windows_[display.id()]->SetHostBounds( | 
| -        GetDisplayManager()->GetDisplayInfo(display).bounds_in_pixel()); | 
| +    const internal::DisplayInfo& display_info = | 
| +        GetDisplayManager()->GetDisplayInfo(display); | 
| +    root_windows_[display.id()]->SetHostBoundsAndInsets( | 
| +        display_info.bounds_in_pixel(), | 
| +        display_info.GetOverscanInsetsInPixel()); | 
| } else { | 
| DCHECK(!root_windows_.empty()); | 
| aura::RootWindow* root = AddRootWindowForDisplay(display); | 
|  |