Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / ash / display / cursor_window_controller.cc
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
24 namespace ash {
25
26 class 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
93 CursorWindowController::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
102 CursorWindowController::~CursorWindowController() {
103   SetContainer(NULL);
104 }
105
106 void 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
115 void CursorWindowController::UpdateContainer() {
116   display_ = Shell::GetScreen()->GetPrimaryDisplay();
117   if (is_cursor_compositing_enabled_) {
118     SetDisplay(display_);
119   } else {
120     SetContainer(Shell::GetInstance()->
121                  display_controller()->
122                  mirror_window_controller()->
123                  GetWindow());
124   }
125 }
126
127 void CursorWindowController::SetDisplay(const gfx::Display& display) {
128   if (!is_cursor_compositing_enabled_)
129     return;
130
131   display_ = display;
132   aura::Window* root_window = Shell::GetInstance()->display_controller()->
133       GetRootWindowForDisplayId(display.id());
134   if (!root_window)
135     return;
136
137   SetContainer(GetRootWindowController(root_window)->GetContainer(
138       kShellWindowId_MouseCursorContainer));
139   SetBoundsInScreen(display.bounds());
140 }
141
142 void CursorWindowController::UpdateLocation() {
143   if (!cursor_window_)
144     return;
145
146   gfx::Point point = aura::Env::GetInstance()->last_mouse_location();
147   if (!is_cursor_compositing_enabled_) {
148     Shell::GetPrimaryRootWindow()->GetHost()->ConvertPointToHost(&point);
149   } else {
150     point.Offset(-bounds_in_screen_.x(), -bounds_in_screen_.y());
151   }
152   point.Offset(-hot_point_.x(), -hot_point_.y());
153   gfx::Rect bounds = cursor_window_->bounds();
154   bounds.set_origin(point);
155   cursor_window_->SetBounds(bounds);
156 }
157
158 void CursorWindowController::SetCursor(gfx::NativeCursor cursor) {
159   if (cursor_type_ == cursor.native_type() &&
160       cursor_rotation_ == display_.rotation())
161     return;
162   cursor_type_ = cursor.native_type();
163   cursor_rotation_ = display_.rotation();
164   UpdateCursorImage();
165 }
166
167 void CursorWindowController::SetCursorSet(ui::CursorSetType cursor_set) {
168   cursor_set_ = cursor_set;
169   UpdateCursorImage();
170 }
171
172 void CursorWindowController::SetVisibility(bool visible) {
173   if (!cursor_window_)
174     return;
175   if (visible)
176     cursor_window_->Show();
177   else
178     cursor_window_->Hide();
179 }
180
181 void CursorWindowController::SetContainer(aura::Window* container) {
182   if (container_ == container)
183     return;
184
185   container_ = container;
186   if (!container) {
187     cursor_window_.reset();
188     return;
189   }
190
191   if (!cursor_window_) {
192     cursor_window_.reset(new aura::Window(delegate_.get()));
193     cursor_window_->SetTransparent(true);
194     cursor_window_->Init(aura::WINDOW_LAYER_TEXTURED);
195     cursor_window_->set_ignore_events(true);
196     cursor_window_->set_owned_by_parent(false);
197   }
198
199   container->AddChild(cursor_window_.get());
200   cursor_window_->Show();
201   SetBoundsInScreen(container->bounds());
202 }
203
204 void CursorWindowController::SetBoundsInScreen(const gfx::Rect& bounds) {
205   bounds_in_screen_ = bounds;
206   UpdateLocation();
207 }
208
209 void CursorWindowController::UpdateCursorImage() {
210   int resource_id;
211   // TODO(hshi): support custom cursor set.
212   if (!ui::GetCursorDataFor(cursor_set_,
213                             cursor_type_,
214                             display_.device_scale_factor(),
215                             &resource_id,
216                             &hot_point_)) {
217     return;
218   }
219   const gfx::ImageSkia* image =
220       ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
221   gfx::ImageSkia rotated = *image;
222   if (!is_cursor_compositing_enabled_) {
223     switch (cursor_rotation_) {
224       case gfx::Display::ROTATE_0:
225         break;
226       case gfx::Display::ROTATE_90:
227         rotated = gfx::ImageSkiaOperations::CreateRotatedImage(
228             *image, SkBitmapOperations::ROTATION_90_CW);
229         hot_point_.SetPoint(
230             rotated.width() - hot_point_.y(),
231             hot_point_.x());
232         break;
233       case gfx::Display::ROTATE_180:
234         rotated = gfx::ImageSkiaOperations::CreateRotatedImage(
235             *image, SkBitmapOperations::ROTATION_180_CW);
236         hot_point_.SetPoint(
237             rotated.height() - hot_point_.x(),
238             rotated.width() - hot_point_.y());
239         break;
240       case gfx::Display::ROTATE_270:
241         rotated = gfx::ImageSkiaOperations::CreateRotatedImage(
242             *image, SkBitmapOperations::ROTATION_270_CW);
243         hot_point_.SetPoint(
244             hot_point_.y(),
245             rotated.height() - hot_point_.x());
246         break;
247     }
248   } else {
249     hot_point_ = ui::ConvertPointToDIP(Shell::GetPrimaryRootWindow()->layer(),
250                                        hot_point_);
251   }
252   delegate_->SetCursorImage(rotated, display_);
253   if (cursor_window_) {
254     cursor_window_->SetBounds(gfx::Rect(delegate_->size()));
255     cursor_window_->SchedulePaintInRect(
256         gfx::Rect(cursor_window_->bounds().size()));
257     UpdateLocation();
258   }
259 }
260
261 }  // namespace ash