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