cursor_window_controller.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
1// Copyright 2014 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/display/cursor_window_controller.h" 6 7#include "ash/display/display_controller.h" 8#include "ash/display/mirror_window_controller.h" 9#include "ash/root_window_controller.h" 10#include "ash/shell.h" 11#include "ash/shell_window_ids.h" 12#include "ui/aura/env.h" 13#include "ui/aura/window_delegate.h" 14#include "ui/aura/window_event_dispatcher.h" 15#include "ui/base/cursor/cursors_aura.h" 16#include "ui/base/hit_test.h" 17#include "ui/base/resource/resource_bundle.h" 18#include "ui/compositor/dip_util.h" 19#include "ui/gfx/canvas.h" 20#include "ui/gfx/display.h" 21#include "ui/gfx/image/image_skia.h" 22#include "ui/gfx/image/image_skia_operations.h" 23 24namespace ash { 25 26class CursorWindowDelegate : public aura::WindowDelegate { 27 public: 28 CursorWindowDelegate() : is_cursor_compositing_enabled_(false) {} 29 virtual ~CursorWindowDelegate() {} 30 31 // aura::WindowDelegate overrides: 32 virtual gfx::Size GetMinimumSize() const OVERRIDE { return size_; } 33 virtual gfx::Size GetMaximumSize() const OVERRIDE { return size_; } 34 virtual void OnBoundsChanged(const gfx::Rect& old_bounds, 35 const gfx::Rect& new_bounds) OVERRIDE {} 36 virtual gfx::NativeCursor GetCursor(const gfx::Point& point) OVERRIDE { 37 return gfx::kNullCursor; 38 } 39 virtual int GetNonClientComponent( 40 const gfx::Point& point) const OVERRIDE { 41 return HTNOWHERE; 42 } 43 virtual bool ShouldDescendIntoChildForEventHandling( 44 aura::Window* child, 45 const gfx::Point& location) OVERRIDE { 46 return false; 47 } 48 virtual bool CanFocus() OVERRIDE { return false; } 49 virtual void OnCaptureLost() OVERRIDE {} 50 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE { 51 canvas->DrawImageInt(cursor_image_, 0, 0); 52 } 53 virtual void OnDeviceScaleFactorChanged( 54 float device_scale_factor) OVERRIDE {} 55 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {} 56 virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {} 57 virtual void OnWindowTargetVisibilityChanged(bool visible) OVERRIDE {} 58 virtual bool HasHitTestMask() const OVERRIDE { return false; } 59 virtual void GetHitTestMask(gfx::Path* mask) const OVERRIDE {} 60 61 // Sets cursor compositing mode on/off. 62 void SetCursorCompositingEnabled(bool enabled) { 63 is_cursor_compositing_enabled_ = enabled; 64 } 65 66 // Sets the cursor image for the |display|'s scale factor. 67 void SetCursorImage(const gfx::ImageSkia& image, 68 const gfx::Display& display) { 69 float scale_factor = display.device_scale_factor(); 70 const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(scale_factor); 71 if (!is_cursor_compositing_enabled_) { 72 // Note that mirror window's scale factor is always 1.0f, therefore we 73 // need to take 2x's image and paint as if it's 1x image. 74 size_ = image_rep.pixel_size(); 75 cursor_image_ = gfx::ImageSkia::CreateFrom1xBitmap(image_rep.sk_bitmap()); 76 } else { 77 size_ = image.size(); 78 cursor_image_ = gfx::ImageSkia( 79 gfx::ImageSkiaRep(image_rep.sk_bitmap(), scale_factor)); 80 } 81 } 82 83 const gfx::Size size() const { return size_; } 84 85 private: 86 bool is_cursor_compositing_enabled_; 87 gfx::ImageSkia cursor_image_; 88 gfx::Size size_; 89 90 DISALLOW_COPY_AND_ASSIGN(CursorWindowDelegate); 91}; 92 93CursorWindowController::CursorWindowController() 94 : is_cursor_compositing_enabled_(false), 95 container_(NULL), 96 cursor_type_(ui::kCursorNone), 97 cursor_set_(ui::CURSOR_SET_NORMAL), 98 cursor_rotation_(gfx::Display::ROTATE_0), 99 delegate_(new CursorWindowDelegate()) { 100} 101 102CursorWindowController::~CursorWindowController() { 103 SetContainer(NULL); 104} 105 106void CursorWindowController::SetCursorCompositingEnabled(bool enabled) { 107 if (is_cursor_compositing_enabled_ != enabled) { 108 is_cursor_compositing_enabled_ = enabled; 109 delegate_->SetCursorCompositingEnabled(enabled); 110 UpdateCursorImage(); 111 UpdateContainer(); 112 } 113} 114 115void CursorWindowController::UpdateContainer() { 116 display_ = Shell::GetScreen()->GetPrimaryDisplay(); 117 if (is_cursor_compositing_enabled_) { 118 SetDisplay(display_); 119 } else { 120 aura::WindowTreeHost* mirror_host = Shell::GetInstance()-> 121 display_controller()->mirror_window_controller()->host(); 122 SetContainer(mirror_host ? mirror_host->window() : NULL); 123 } 124} 125 126void CursorWindowController::SetDisplay(const gfx::Display& display) { 127 if (!is_cursor_compositing_enabled_) 128 return; 129 130 display_ = display; 131 aura::Window* root_window = Shell::GetInstance()->display_controller()-> 132 GetRootWindowForDisplayId(display.id()); 133 if (!root_window) 134 return; 135 136 SetContainer(GetRootWindowController(root_window)->GetContainer( 137 kShellWindowId_MouseCursorContainer)); 138 SetBoundsInScreen(display.bounds()); 139} 140 141void CursorWindowController::UpdateLocation() { 142 if (!cursor_window_) 143 return; 144 145 gfx::Point point = aura::Env::GetInstance()->last_mouse_location(); 146 if (!is_cursor_compositing_enabled_) { 147 Shell::GetPrimaryRootWindow()->GetHost()->ConvertPointToHost(&point); 148 } else { 149 point.Offset(-bounds_in_screen_.x(), -bounds_in_screen_.y()); 150 } 151 point.Offset(-hot_point_.x(), -hot_point_.y()); 152 gfx::Rect bounds = cursor_window_->bounds(); 153 bounds.set_origin(point); 154 cursor_window_->SetBounds(bounds); 155} 156 157void CursorWindowController::SetCursor(gfx::NativeCursor cursor) { 158 if (cursor_type_ == cursor.native_type() && 159 cursor_rotation_ == display_.rotation()) 160 return; 161 cursor_type_ = cursor.native_type(); 162 cursor_rotation_ = display_.rotation(); 163 UpdateCursorImage(); 164} 165 166void CursorWindowController::SetCursorSet(ui::CursorSetType cursor_set) { 167 cursor_set_ = cursor_set; 168 UpdateCursorImage(); 169} 170 171void CursorWindowController::SetVisibility(bool visible) { 172 if (!cursor_window_) 173 return; 174 if (visible) 175 cursor_window_->Show(); 176 else 177 cursor_window_->Hide(); 178} 179 180void CursorWindowController::SetContainer(aura::Window* container) { 181 if (container_ == container) 182 return; 183 184 container_ = container; 185 if (!container) { 186 cursor_window_.reset(); 187 return; 188 } 189 190 if (!cursor_window_) { 191 cursor_window_.reset(new aura::Window(delegate_.get())); 192 cursor_window_->SetTransparent(true); 193 cursor_window_->Init(aura::WINDOW_LAYER_TEXTURED); 194 cursor_window_->set_ignore_events(true); 195 cursor_window_->set_owned_by_parent(false); 196 } 197 198 container->AddChild(cursor_window_.get()); 199 cursor_window_->Show(); 200 SetBoundsInScreen(container->bounds()); 201} 202 203void CursorWindowController::SetBoundsInScreen(const gfx::Rect& bounds) { 204 bounds_in_screen_ = bounds; 205 UpdateLocation(); 206} 207 208void CursorWindowController::UpdateCursorImage() { 209 int resource_id; 210 // TODO(hshi): support custom cursor set. 211 if (!ui::GetCursorDataFor(cursor_set_, 212 cursor_type_, 213 display_.device_scale_factor(), 214 &resource_id, 215 &hot_point_)) { 216 return; 217 } 218 const gfx::ImageSkia* image = 219 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); 220 gfx::ImageSkia rotated = *image; 221 if (!is_cursor_compositing_enabled_) { 222 switch (cursor_rotation_) { 223 case gfx::Display::ROTATE_0: 224 break; 225 case gfx::Display::ROTATE_90: 226 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 227 *image, SkBitmapOperations::ROTATION_90_CW); 228 hot_point_.SetPoint( 229 rotated.width() - hot_point_.y(), 230 hot_point_.x()); 231 break; 232 case gfx::Display::ROTATE_180: 233 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 234 *image, SkBitmapOperations::ROTATION_180_CW); 235 hot_point_.SetPoint( 236 rotated.height() - hot_point_.x(), 237 rotated.width() - hot_point_.y()); 238 break; 239 case gfx::Display::ROTATE_270: 240 rotated = gfx::ImageSkiaOperations::CreateRotatedImage( 241 *image, SkBitmapOperations::ROTATION_270_CW); 242 hot_point_.SetPoint( 243 hot_point_.y(), 244 rotated.height() - hot_point_.x()); 245 break; 246 } 247 } else { 248 hot_point_ = ui::ConvertPointToDIP(Shell::GetPrimaryRootWindow()->layer(), 249 hot_point_); 250 } 251 delegate_->SetCursorImage(rotated, display_); 252 if (cursor_window_) { 253 cursor_window_->SetBounds(gfx::Rect(delegate_->size())); 254 cursor_window_->SchedulePaintInRect( 255 gfx::Rect(cursor_window_->bounds().size())); 256 UpdateLocation(); 257 } 258} 259 260} // namespace ash 261