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 "ash/desktop_background/desktop_background_view.h" 6 7 #include <limits> 8 9 #include "ash/ash_export.h" 10 #include "ash/desktop_background/desktop_background_controller.h" 11 #include "ash/desktop_background/desktop_background_widget_controller.h" 12 #include "ash/desktop_background/user_wallpaper_delegate.h" 13 #include "ash/display/display_manager.h" 14 #include "ash/root_window_controller.h" 15 #include "ash/session_state_delegate.h" 16 #include "ash/shell.h" 17 #include "ash/shell_window_ids.h" 18 #include "ash/wm/property_util.h" 19 #include "ash/wm/window_animations.h" 20 #include "base/message_loop/message_loop.h" 21 #include "base/strings/utf_string_conversions.h" 22 #include "ui/aura/root_window.h" 23 #include "ui/base/resource/resource_bundle.h" 24 #include "ui/compositor/layer.h" 25 #include "ui/gfx/canvas.h" 26 #include "ui/gfx/image/image.h" 27 #include "ui/views/widget/widget.h" 28 29 namespace ash { 30 namespace internal { 31 namespace { 32 33 // For our scaling ratios we need to round positive numbers. 34 int RoundPositive(double x) { 35 return static_cast<int>(floor(x + 0.5)); 36 } 37 38 } // namespace 39 40 //////////////////////////////////////////////////////////////////////////////// 41 // DesktopBackgroundView, public: 42 43 DesktopBackgroundView::DesktopBackgroundView() { 44 set_context_menu_controller(this); 45 } 46 47 DesktopBackgroundView::~DesktopBackgroundView() { 48 } 49 50 //////////////////////////////////////////////////////////////////////////////// 51 // DesktopBackgroundView, views::View overrides: 52 53 void DesktopBackgroundView::OnPaint(gfx::Canvas* canvas) { 54 // Scale the image while maintaining the aspect ratio, cropping as 55 // necessary to fill the background. Ideally the image should be larger 56 // than the largest display supported, if not we will center it rather than 57 // streching to avoid upsampling artifacts (Note that we could tile too, but 58 // decided not to do this at the moment). 59 DesktopBackgroundController* controller = 60 Shell::GetInstance()->desktop_background_controller(); 61 gfx::ImageSkia wallpaper = controller->GetWallpaper(); 62 WallpaperLayout wallpaper_layout = controller->GetWallpaperLayout(); 63 64 gfx::NativeView native_view = GetWidget()->GetNativeView(); 65 gfx::Display display = gfx::Screen::GetScreenFor(native_view)-> 66 GetDisplayNearestWindow(native_view); 67 68 DisplayManager* display_manager = Shell::GetInstance()->display_manager(); 69 DisplayInfo display_info = display_manager->GetDisplayInfo(display.id()); 70 float scaling = display_info.ui_scale(); 71 if (scaling <= 1.0f) 72 scaling = 1.0f; 73 // Allow scaling up to the UI scaling. 74 // TODO(oshima): Create separate layer that fits to the image and then 75 // scale to avoid artifacts and be more efficient when clipped. 76 gfx::Rect wallpaper_rect( 77 0, 0, wallpaper.width() * scaling, wallpaper.height() * scaling); 78 79 if (wallpaper_layout == WALLPAPER_LAYOUT_CENTER_CROPPED && 80 wallpaper_rect.width() >= width() && 81 wallpaper_rect.height() >= height()) { 82 // The dimension with the smallest ratio must be cropped, the other one 83 // is preserved. Both are set in gfx::Size cropped_size. 84 double horizontal_ratio = static_cast<double>(width()) / 85 static_cast<double>(wallpaper.width()); 86 double vertical_ratio = static_cast<double>(height()) / 87 static_cast<double>(wallpaper.height()); 88 89 gfx::Size cropped_size; 90 if (vertical_ratio > horizontal_ratio) { 91 cropped_size = gfx::Size( 92 RoundPositive(static_cast<double>(width()) / vertical_ratio), 93 wallpaper.height()); 94 } else { 95 cropped_size = gfx::Size(wallpaper.width(), 96 RoundPositive(static_cast<double>(height()) / horizontal_ratio)); 97 } 98 99 gfx::Rect wallpaper_cropped_rect( 100 0, 0, wallpaper.width(), wallpaper.height()); 101 wallpaper_cropped_rect.ClampToCenteredSize(cropped_size); 102 canvas->DrawImageInt(wallpaper, 103 wallpaper_cropped_rect.x(), wallpaper_cropped_rect.y(), 104 wallpaper_cropped_rect.width(), wallpaper_cropped_rect.height(), 105 0, 0, width(), height(), 106 true); 107 } else if (wallpaper_layout == WALLPAPER_LAYOUT_TILE) { 108 canvas->TileImageInt(wallpaper, 0, 0, width(), height()); 109 } else if (wallpaper_layout == WALLPAPER_LAYOUT_STRETCH) { 110 // This is generally not recommended as it may show artifacts. 111 canvas->DrawImageInt(wallpaper, 0, 0, wallpaper.width(), 112 wallpaper.height(), 0, 0, width(), height(), true); 113 } else { 114 // Fill with black to make sure that the entire area is opaque. 115 canvas->FillRect(GetLocalBounds(), SK_ColorBLACK); 116 // All other are simply centered, and not scaled (but may be clipped). 117 if (wallpaper.width() && wallpaper.height()) { 118 canvas->DrawImageInt( 119 wallpaper, 120 0, 0, wallpaper.width(), wallpaper.height(), 121 (width() - wallpaper_rect.width()) / 2, 122 (height() - wallpaper_rect.height()) / 2, 123 wallpaper_rect.width(), 124 wallpaper_rect.height(), 125 true); 126 } 127 } 128 } 129 130 bool DesktopBackgroundView::OnMousePressed(const ui::MouseEvent& event) { 131 return true; 132 } 133 134 void DesktopBackgroundView::ShowContextMenuForView( 135 views::View* source, 136 const gfx::Point& point, 137 ui::MenuSourceType source_type) { 138 Shell::GetInstance()->ShowContextMenu(point, source_type); 139 } 140 141 views::Widget* CreateDesktopBackground(aura::RootWindow* root_window, 142 int container_id) { 143 DesktopBackgroundController* controller = 144 Shell::GetInstance()->desktop_background_controller(); 145 UserWallpaperDelegate* wallpaper_delegate = 146 Shell::GetInstance()->user_wallpaper_delegate(); 147 148 views::Widget* desktop_widget = new views::Widget; 149 views::Widget::InitParams params( 150 views::Widget::InitParams::TYPE_WINDOW_FRAMELESS); 151 if (controller->GetWallpaper().isNull()) 152 params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; 153 params.parent = root_window->GetChildById(container_id); 154 desktop_widget->Init(params); 155 desktop_widget->SetContentsView(new DesktopBackgroundView()); 156 int animation_type = wallpaper_delegate->GetAnimationType(); 157 views::corewm::SetWindowVisibilityAnimationType( 158 desktop_widget->GetNativeView(), animation_type); 159 160 RootWindowController* root_window_controller = 161 GetRootWindowController(root_window); 162 163 // Enable wallpaper transition for the following cases: 164 // 1. Initial(OOBE) wallpaper animation. 165 // 2. Wallpaper fades in from a non empty background. 166 // 3. From an empty background, chrome transit to a logged in user session. 167 // 4. From an empty background, guest user logged in. 168 if (wallpaper_delegate->ShouldShowInitialAnimation() || 169 root_window_controller->animating_wallpaper_controller() || 170 Shell::GetInstance()->session_state_delegate()->NumberOfLoggedInUsers()) { 171 views::corewm::SetWindowVisibilityAnimationTransition( 172 desktop_widget->GetNativeView(), views::corewm::ANIMATE_SHOW); 173 } else { 174 // Disable animation if transition to login screen from an empty background. 175 views::corewm::SetWindowVisibilityAnimationTransition( 176 desktop_widget->GetNativeView(), views::corewm::ANIMATE_NONE); 177 } 178 179 desktop_widget->SetBounds(params.parent->bounds()); 180 return desktop_widget; 181 } 182 183 } // namespace internal 184 } // namespace ash 185