Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / ui / base / cursor / cursor_loader_x11.cc
blob47ed9d9e113973a14b2f9ececc278bbdbe0b17a2
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.
5 #include "ui/base/cursor/cursor_loader_x11.h"
7 #include <float.h>
8 #include <X11/Xlib.h>
9 #include <X11/cursorfont.h>
11 #include "base/logging.h"
12 #include "skia/ext/image_operations.h"
13 #include "ui/base/cursor/cursor.h"
14 #include "ui/base/cursor/cursor_util.h"
15 #include "ui/base/resource/resource_bundle.h"
16 #include "ui/base/x/x11_util.h"
17 #include "ui/gfx/image/image.h"
18 #include "ui/gfx/image/image_skia.h"
19 #include "ui/gfx/point_conversions.h"
20 #include "ui/gfx/size_conversions.h"
21 #include "ui/gfx/skbitmap_operations.h"
22 #include "ui/gfx/skia_util.h"
24 namespace {
26 // Returns X font cursor shape from an Aura cursor.
27 int CursorShapeFromNative(const gfx::NativeCursor& native_cursor) {
28 switch (native_cursor.native_type()) {
29 case ui::kCursorMiddlePanning:
30 return XC_fleur;
31 case ui::kCursorEastPanning:
32 return XC_sb_right_arrow;
33 case ui::kCursorNorthPanning:
34 return XC_sb_up_arrow;
35 case ui::kCursorNorthEastPanning:
36 return XC_top_right_corner;
37 case ui::kCursorNorthWestPanning:
38 return XC_top_left_corner;
39 case ui::kCursorSouthPanning:
40 return XC_sb_down_arrow;
41 case ui::kCursorSouthEastPanning:
42 return XC_bottom_right_corner;
43 case ui::kCursorSouthWestPanning:
44 return XC_bottom_left_corner;
45 case ui::kCursorWestPanning:
46 return XC_sb_left_arrow;
47 case ui::kCursorNone:
48 case ui::kCursorGrab:
49 case ui::kCursorGrabbing:
50 // TODO(jamescook): Need cursors for these. crbug.com/111650
51 return XC_left_ptr;
53 #if defined(OS_CHROMEOS)
54 case ui::kCursorNull:
55 case ui::kCursorPointer:
56 case ui::kCursorNoDrop:
57 case ui::kCursorNotAllowed:
58 case ui::kCursorCopy:
59 case ui::kCursorMove:
60 case ui::kCursorEastResize:
61 case ui::kCursorNorthResize:
62 case ui::kCursorSouthResize:
63 case ui::kCursorWestResize:
64 case ui::kCursorNorthEastResize:
65 case ui::kCursorNorthWestResize:
66 case ui::kCursorSouthWestResize:
67 case ui::kCursorSouthEastResize:
68 case ui::kCursorIBeam:
69 case ui::kCursorAlias:
70 case ui::kCursorCell:
71 case ui::kCursorContextMenu:
72 case ui::kCursorCross:
73 case ui::kCursorHelp:
74 case ui::kCursorWait:
75 case ui::kCursorNorthSouthResize:
76 case ui::kCursorEastWestResize:
77 case ui::kCursorNorthEastSouthWestResize:
78 case ui::kCursorNorthWestSouthEastResize:
79 case ui::kCursorProgress:
80 case ui::kCursorColumnResize:
81 case ui::kCursorRowResize:
82 case ui::kCursorVerticalText:
83 case ui::kCursorZoomIn:
84 case ui::kCursorZoomOut:
85 case ui::kCursorHand:
86 // In some environments, the image assets are not set (e.g. in
87 // content-browsertests, content-shell etc.).
88 return XC_left_ptr;
89 #else // defined(OS_CHROMEOS)
90 case ui::kCursorNull:
91 return XC_left_ptr;
92 case ui::kCursorPointer:
93 return XC_left_ptr;
94 case ui::kCursorMove:
95 return XC_fleur;
96 case ui::kCursorCross:
97 return XC_crosshair;
98 case ui::kCursorHand:
99 return XC_hand2;
100 case ui::kCursorIBeam:
101 return XC_xterm;
102 case ui::kCursorProgress:
103 case ui::kCursorWait:
104 return XC_watch;
105 case ui::kCursorHelp:
106 return XC_question_arrow;
107 case ui::kCursorEastResize:
108 return XC_right_side;
109 case ui::kCursorNorthResize:
110 return XC_top_side;
111 case ui::kCursorNorthEastResize:
112 return XC_top_right_corner;
113 case ui::kCursorNorthWestResize:
114 return XC_top_left_corner;
115 case ui::kCursorSouthResize:
116 return XC_bottom_side;
117 case ui::kCursorSouthEastResize:
118 return XC_bottom_right_corner;
119 case ui::kCursorSouthWestResize:
120 return XC_bottom_left_corner;
121 case ui::kCursorWestResize:
122 return XC_left_side;
123 case ui::kCursorNorthSouthResize:
124 return XC_sb_v_double_arrow;
125 case ui::kCursorEastWestResize:
126 return XC_sb_h_double_arrow;
127 case ui::kCursorColumnResize:
128 return XC_sb_h_double_arrow;
129 case ui::kCursorRowResize:
130 return XC_sb_v_double_arrow;
131 #endif // defined(OS_CHROMEOS)
132 case ui::kCursorCustom:
133 NOTREACHED();
134 return XC_left_ptr;
136 NOTREACHED() << "Case not handled for " << native_cursor.native_type();
137 return XC_left_ptr;
140 } // namespace
142 namespace ui {
144 CursorLoader* CursorLoader::Create() {
145 return new CursorLoaderX11;
148 CursorLoaderX11::CursorLoaderX11()
149 : invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) {
152 CursorLoaderX11::~CursorLoaderX11() {
153 UnloadAll();
156 void CursorLoaderX11::LoadImageCursor(int id,
157 int resource_id,
158 const gfx::Point& hot) {
159 const gfx::ImageSkia* image =
160 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
161 const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(scale());
162 SkBitmap bitmap = image_rep.sk_bitmap();
163 gfx::Point hotpoint = hot;
164 // TODO(oshima): The cursor should use resource scale factor when
165 // fractional scale factor is enabled. crbug.com/372212
166 ScaleAndRotateCursorBitmapAndHotpoint(
167 scale() / image_rep.scale(), rotation(), &bitmap, &hotpoint);
169 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmap, hotpoint);
170 cursors_[id] = CreateReffedCustomXCursor(x_image);
171 // |image_rep| is owned by the resource bundle. So we do not need to free it.
174 void CursorLoaderX11::LoadAnimatedCursor(int id,
175 int resource_id,
176 const gfx::Point& hot,
177 int frame_delay_ms) {
178 // TODO(oshima|tdanderson): Support rotation and fractional scale factor.
179 const gfx::ImageSkia* image =
180 ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id);
181 const gfx::ImageSkiaRep& image_rep = image->GetRepresentation(scale());
182 SkBitmap bitmap = image_rep.sk_bitmap();
183 int frame_width = bitmap.height();
184 int frame_height = frame_width;
185 int total_width = bitmap.width();
186 DCHECK_EQ(total_width % frame_width, 0);
187 int frame_count = total_width / frame_width;
188 DCHECK_GT(frame_count, 0);
189 XcursorImages* x_images = XcursorImagesCreate(frame_count);
190 x_images->nimage = frame_count;
192 for (int frame = 0; frame < frame_count; ++frame) {
193 gfx::Point hotpoint = hot;
194 int x_offset = frame_width * frame;
195 DCHECK_LE(x_offset + frame_width, total_width);
197 SkBitmap cropped = SkBitmapOperations::CreateTiledBitmap(
198 bitmap, x_offset, 0, frame_width, frame_height);
199 DCHECK_EQ(frame_width, cropped.width());
200 DCHECK_EQ(frame_height, cropped.height());
202 XcursorImage* x_image = SkBitmapToXcursorImage(&cropped, hotpoint);
204 x_image->delay = frame_delay_ms;
205 x_images->images[frame] = x_image;
208 animated_cursors_[id] = std::make_pair(
209 XcursorImagesLoadCursor(gfx::GetXDisplay(), x_images), x_images);
210 // |bitmap| is owned by the resource bundle. So we do not need to free it.
213 void CursorLoaderX11::UnloadAll() {
214 for (ImageCursorMap::const_iterator it = cursors_.begin();
215 it != cursors_.end(); ++it)
216 UnrefCustomXCursor(it->second);
218 // Free animated cursors and images.
219 for (AnimatedCursorMap::iterator it = animated_cursors_.begin();
220 it != animated_cursors_.end(); ++it) {
221 XcursorImagesDestroy(it->second.second); // also frees individual frames.
222 XFreeCursor(gfx::GetXDisplay(), it->second.first);
226 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
227 DCHECK(cursor);
229 ::Cursor xcursor;
230 if (IsImageCursor(*cursor))
231 xcursor = ImageCursorFromNative(*cursor);
232 else if (*cursor == kCursorNone)
233 xcursor = invisible_cursor_.get();
234 else if (*cursor == kCursorCustom)
235 xcursor = cursor->platform();
236 else if (scale() == 1.0f && rotation() == gfx::Display::ROTATE_0) {
237 xcursor = GetXCursor(CursorShapeFromNative(*cursor));
238 } else {
239 xcursor = ImageCursorFromNative(kCursorPointer);
242 cursor->SetPlatformCursor(xcursor);
245 const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) {
246 return test::GetCachedXcursorImage(cursors_[id]);
249 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
250 int type = native_cursor.native_type();
251 return cursors_.count(type) || animated_cursors_.count(type);
254 ::Cursor CursorLoaderX11::ImageCursorFromNative(
255 gfx::NativeCursor native_cursor) {
256 int type = native_cursor.native_type();
257 if (animated_cursors_.count(type))
258 return animated_cursors_[type].first;
260 ImageCursorMap::iterator find = cursors_.find(type);
261 if (find != cursors_.end())
262 return cursors_[type];
263 return GetXCursor(CursorShapeFromNative(native_cursor));
266 } // namespace ui