Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / ui / base / cursor / cursor_loader_x11.cc
blob8ad1f0e3e1d5e40ff755d638a10e4cd0e513baf5
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/cursorfont.h>
9 #include <X11/Xlib.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/x/x11_util.h"
16 #include "ui/gfx/geometry/point_conversions.h"
17 #include "ui/gfx/geometry/size_conversions.h"
18 #include "ui/gfx/image/image.h"
19 #include "ui/gfx/skbitmap_operations.h"
20 #include "ui/gfx/skia_util.h"
22 namespace {
24 // Returns X font cursor shape from an Aura cursor.
25 int CursorShapeFromNative(const gfx::NativeCursor& native_cursor) {
26 switch (native_cursor.native_type()) {
27 case ui::kCursorMiddlePanning:
28 return XC_fleur;
29 case ui::kCursorEastPanning:
30 return XC_sb_right_arrow;
31 case ui::kCursorNorthPanning:
32 return XC_sb_up_arrow;
33 case ui::kCursorNorthEastPanning:
34 return XC_top_right_corner;
35 case ui::kCursorNorthWestPanning:
36 return XC_top_left_corner;
37 case ui::kCursorSouthPanning:
38 return XC_sb_down_arrow;
39 case ui::kCursorSouthEastPanning:
40 return XC_bottom_right_corner;
41 case ui::kCursorSouthWestPanning:
42 return XC_bottom_left_corner;
43 case ui::kCursorWestPanning:
44 return XC_sb_left_arrow;
45 case ui::kCursorNone:
46 case ui::kCursorGrab:
47 case ui::kCursorGrabbing:
48 // TODO(jamescook): Need cursors for these. crbug.com/111650
49 return XC_left_ptr;
51 #if defined(OS_CHROMEOS)
52 case ui::kCursorNull:
53 case ui::kCursorPointer:
54 case ui::kCursorNoDrop:
55 case ui::kCursorNotAllowed:
56 case ui::kCursorCopy:
57 case ui::kCursorMove:
58 case ui::kCursorEastResize:
59 case ui::kCursorNorthResize:
60 case ui::kCursorSouthResize:
61 case ui::kCursorWestResize:
62 case ui::kCursorNorthEastResize:
63 case ui::kCursorNorthWestResize:
64 case ui::kCursorSouthWestResize:
65 case ui::kCursorSouthEastResize:
66 case ui::kCursorIBeam:
67 case ui::kCursorAlias:
68 case ui::kCursorCell:
69 case ui::kCursorContextMenu:
70 case ui::kCursorCross:
71 case ui::kCursorHelp:
72 case ui::kCursorWait:
73 case ui::kCursorNorthSouthResize:
74 case ui::kCursorEastWestResize:
75 case ui::kCursorNorthEastSouthWestResize:
76 case ui::kCursorNorthWestSouthEastResize:
77 case ui::kCursorProgress:
78 case ui::kCursorColumnResize:
79 case ui::kCursorRowResize:
80 case ui::kCursorVerticalText:
81 case ui::kCursorZoomIn:
82 case ui::kCursorZoomOut:
83 case ui::kCursorHand:
84 // In some environments, the image assets are not set (e.g. in
85 // content-browsertests, content-shell etc.).
86 return XC_left_ptr;
87 #else // defined(OS_CHROMEOS)
88 case ui::kCursorNull:
89 return XC_left_ptr;
90 case ui::kCursorPointer:
91 return XC_left_ptr;
92 case ui::kCursorMove:
93 return XC_fleur;
94 case ui::kCursorCross:
95 return XC_crosshair;
96 case ui::kCursorHand:
97 return XC_hand2;
98 case ui::kCursorIBeam:
99 return XC_xterm;
100 case ui::kCursorProgress:
101 case ui::kCursorWait:
102 return XC_watch;
103 case ui::kCursorHelp:
104 return XC_question_arrow;
105 case ui::kCursorEastResize:
106 return XC_right_side;
107 case ui::kCursorNorthResize:
108 return XC_top_side;
109 case ui::kCursorNorthEastResize:
110 return XC_top_right_corner;
111 case ui::kCursorNorthWestResize:
112 return XC_top_left_corner;
113 case ui::kCursorSouthResize:
114 return XC_bottom_side;
115 case ui::kCursorSouthEastResize:
116 return XC_bottom_right_corner;
117 case ui::kCursorSouthWestResize:
118 return XC_bottom_left_corner;
119 case ui::kCursorWestResize:
120 return XC_left_side;
121 case ui::kCursorNorthSouthResize:
122 return XC_sb_v_double_arrow;
123 case ui::kCursorEastWestResize:
124 return XC_sb_h_double_arrow;
125 case ui::kCursorColumnResize:
126 return XC_sb_h_double_arrow;
127 case ui::kCursorRowResize:
128 return XC_sb_v_double_arrow;
129 #endif // defined(OS_CHROMEOS)
130 case ui::kCursorCustom:
131 NOTREACHED();
132 return XC_left_ptr;
134 NOTREACHED() << "Case not handled for " << native_cursor.native_type();
135 return XC_left_ptr;
138 } // namespace
140 namespace ui {
142 CursorLoader* CursorLoader::Create() {
143 return new CursorLoaderX11;
146 CursorLoaderX11::CursorLoaderX11()
147 : invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) {
150 CursorLoaderX11::~CursorLoaderX11() {
151 UnloadAll();
154 void CursorLoaderX11::LoadImageCursor(int id,
155 int resource_id,
156 const gfx::Point& hot) {
157 SkBitmap bitmap;
158 gfx::Point hotspot = hot;
160 GetImageCursorBitmap(resource_id, scale(), rotation(), &hotspot, &bitmap);
161 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmap, hotspot);
162 cursors_[id] = CreateReffedCustomXCursor(x_image);
165 void CursorLoaderX11::LoadAnimatedCursor(int id,
166 int resource_id,
167 const gfx::Point& hot,
168 int frame_delay_ms) {
169 std::vector<SkBitmap> bitmaps;
170 gfx::Point hotspot = hot;
172 GetAnimatedCursorBitmaps(
173 resource_id, scale(), rotation(), &hotspot, &bitmaps);
175 XcursorImages* x_images = XcursorImagesCreate(bitmaps.size());
176 x_images->nimage = bitmaps.size();
178 for (unsigned int frame = 0; frame < bitmaps.size(); ++frame) {
179 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmaps[frame], hotspot);
180 x_image->delay = frame_delay_ms;
181 x_images->images[frame] = x_image;
184 animated_cursors_[id] = std::make_pair(
185 XcursorImagesLoadCursor(gfx::GetXDisplay(), x_images), x_images);
188 void CursorLoaderX11::UnloadAll() {
189 for (ImageCursorMap::const_iterator it = cursors_.begin();
190 it != cursors_.end(); ++it)
191 UnrefCustomXCursor(it->second);
193 // Free animated cursors and images.
194 for (AnimatedCursorMap::iterator it = animated_cursors_.begin();
195 it != animated_cursors_.end(); ++it) {
196 XcursorImagesDestroy(it->second.second); // also frees individual frames.
197 XFreeCursor(gfx::GetXDisplay(), it->second.first);
201 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
202 DCHECK(cursor);
204 ::Cursor xcursor;
205 if (IsImageCursor(*cursor))
206 xcursor = ImageCursorFromNative(*cursor);
207 else if (*cursor == kCursorNone)
208 xcursor = invisible_cursor_.get();
209 else if (*cursor == kCursorCustom)
210 xcursor = cursor->platform();
211 else if (scale() == 1.0f && rotation() == gfx::Display::ROTATE_0) {
212 xcursor = GetXCursor(CursorShapeFromNative(*cursor));
213 } else {
214 xcursor = ImageCursorFromNative(kCursorPointer);
217 cursor->SetPlatformCursor(xcursor);
220 const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) {
221 return test::GetCachedXcursorImage(cursors_[id]);
224 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
225 int type = native_cursor.native_type();
226 return cursors_.count(type) || animated_cursors_.count(type);
229 ::Cursor CursorLoaderX11::ImageCursorFromNative(
230 gfx::NativeCursor native_cursor) {
231 int type = native_cursor.native_type();
232 if (animated_cursors_.count(type))
233 return animated_cursors_[type].first;
235 ImageCursorMap::iterator find = cursors_.find(type);
236 if (find != cursors_.end())
237 return cursors_[type];
238 return GetXCursor(CursorShapeFromNative(native_cursor));
241 } // namespace ui