Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1955)

Side by Side Diff: ui/base/cursor/cursor_loader_x11.cc

Issue 2504743002: Linux Aura: Fixes and improvements for cursor loader (Closed)
Patch Set: Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/base/cursor/cursor_loader_x11.h" 5 #include "ui/base/cursor/cursor_loader_x11.h"
6 6
7 #include <float.h> 7 #include <float.h>
8 #include <X11/cursorfont.h> 8 #include <X11/cursorfont.h>
9 #include <X11/Xlib.h> 9 #include <X11/Xlib.h>
10 10
11 #include "base/logging.h" 11 #include "base/logging.h"
12 #include "build/build_config.h" 12 #include "build/build_config.h"
13 #include "skia/ext/image_operations.h" 13 #include "skia/ext/image_operations.h"
14 #include "ui/base/cursor/cursor.h" 14 #include "ui/base/cursor/cursor.h"
15 #include "ui/base/cursor/cursor_util.h" 15 #include "ui/base/cursor/cursor_util.h"
16 #include "ui/base/cursor/cursors_aura.h"
16 #include "ui/base/x/x11_util.h" 17 #include "ui/base/x/x11_util.h"
17 #include "ui/display/display.h" 18 #include "ui/display/display.h"
18 #include "ui/gfx/geometry/point_conversions.h" 19 #include "ui/gfx/geometry/point_conversions.h"
19 #include "ui/gfx/geometry/size_conversions.h" 20 #include "ui/gfx/geometry/size_conversions.h"
20 #include "ui/gfx/image/image.h" 21 #include "ui/gfx/image/image.h"
21 #include "ui/gfx/skbitmap_operations.h" 22 #include "ui/gfx/skbitmap_operations.h"
22 #include "ui/gfx/skia_util.h" 23 #include "ui/gfx/skia_util.h"
23 24
24 namespace { 25 namespace {
25 26
26 // Returns X font cursor shape from an Aura cursor. 27 // Returns CSS cursor name from an Aura cursor ID.
27 int CursorShapeFromNative(const gfx::NativeCursor& native_cursor) { 28 const char* CursorCssNameFromId(int id) {
28 switch (native_cursor.native_type()) { 29 switch (id) {
29 case ui::kCursorMiddlePanning: 30 case ui::kCursorMiddlePanning:
30 return XC_fleur;
31 case ui::kCursorEastPanning: 31 case ui::kCursorEastPanning:
32 return XC_sb_right_arrow;
33 case ui::kCursorNorthPanning: 32 case ui::kCursorNorthPanning:
34 return XC_sb_up_arrow;
35 case ui::kCursorNorthEastPanning: 33 case ui::kCursorNorthEastPanning:
36 return XC_top_right_corner;
37 case ui::kCursorNorthWestPanning: 34 case ui::kCursorNorthWestPanning:
38 return XC_top_left_corner;
39 case ui::kCursorSouthPanning: 35 case ui::kCursorSouthPanning:
40 return XC_sb_down_arrow;
41 case ui::kCursorSouthEastPanning: 36 case ui::kCursorSouthEastPanning:
42 return XC_bottom_right_corner;
43 case ui::kCursorSouthWestPanning: 37 case ui::kCursorSouthWestPanning:
44 return XC_bottom_left_corner;
45 case ui::kCursorWestPanning: 38 case ui::kCursorWestPanning:
46 return XC_sb_left_arrow; 39 NOTREACHED() << "There's no middle-click panning on Linux or ChromeOS";
40 return "left_ptr";
47 case ui::kCursorNone: 41 case ui::kCursorNone:
42 return "none";
48 case ui::kCursorGrab: 43 case ui::kCursorGrab:
44 return "grab";
49 case ui::kCursorGrabbing: 45 case ui::kCursorGrabbing:
50 // TODO(jamescook): Need cursors for these. crbug.com/111650 46 return "grabbing";
51 return XC_left_ptr;
52 47
53 #if defined(OS_CHROMEOS) 48 #if defined(OS_CHROMEOS)
54 case ui::kCursorNull: 49 case ui::kCursorNull:
55 case ui::kCursorPointer: 50 case ui::kCursorPointer:
56 case ui::kCursorNoDrop: 51 case ui::kCursorNoDrop:
57 case ui::kCursorNotAllowed: 52 case ui::kCursorNotAllowed:
58 case ui::kCursorCopy: 53 case ui::kCursorCopy:
59 case ui::kCursorMove: 54 case ui::kCursorMove:
60 case ui::kCursorEastResize: 55 case ui::kCursorEastResize:
61 case ui::kCursorNorthResize: 56 case ui::kCursorNorthResize:
(...skipping 16 matching lines...) Expand all
78 case ui::kCursorNorthWestSouthEastResize: 73 case ui::kCursorNorthWestSouthEastResize:
79 case ui::kCursorProgress: 74 case ui::kCursorProgress:
80 case ui::kCursorColumnResize: 75 case ui::kCursorColumnResize:
81 case ui::kCursorRowResize: 76 case ui::kCursorRowResize:
82 case ui::kCursorVerticalText: 77 case ui::kCursorVerticalText:
83 case ui::kCursorZoomIn: 78 case ui::kCursorZoomIn:
84 case ui::kCursorZoomOut: 79 case ui::kCursorZoomOut:
85 case ui::kCursorHand: 80 case ui::kCursorHand:
86 // In some environments, the image assets are not set (e.g. in 81 // In some environments, the image assets are not set (e.g. in
87 // content-browsertests, content-shell etc.). 82 // content-browsertests, content-shell etc.).
88 return XC_left_ptr; 83 return "left_ptr";
89 #else // defined(OS_CHROMEOS) 84 #else // defined(OS_CHROMEOS)
90 case ui::kCursorNull: 85 case ui::kCursorNull:
91 return XC_left_ptr; 86 return "left_ptr";
92 case ui::kCursorPointer: 87 case ui::kCursorPointer:
93 return XC_left_ptr; 88 return "left_ptr";
94 case ui::kCursorMove: 89 case ui::kCursorMove:
95 return XC_fleur; 90 return "move";
96 case ui::kCursorCross: 91 case ui::kCursorCross:
97 return XC_crosshair; 92 return "crosshair";
98 case ui::kCursorHand: 93 case ui::kCursorHand:
99 return XC_hand2; 94 return "pointer";
100 case ui::kCursorIBeam: 95 case ui::kCursorIBeam:
101 return XC_xterm; 96 return "text";
102 case ui::kCursorProgress: 97 case ui::kCursorProgress:
98 return "progress";
103 case ui::kCursorWait: 99 case ui::kCursorWait:
104 return XC_watch; 100 return "wait";
105 case ui::kCursorHelp: 101 case ui::kCursorHelp:
106 return XC_question_arrow; 102 return "help";
107 case ui::kCursorEastResize: 103 case ui::kCursorEastResize:
108 return XC_right_side; 104 return "e-resize";
109 case ui::kCursorNorthResize: 105 case ui::kCursorNorthResize:
110 return XC_top_side; 106 return "n-resize";
111 case ui::kCursorNorthEastResize: 107 case ui::kCursorNorthEastResize:
112 return XC_top_right_corner; 108 return "ne-resize";
113 case ui::kCursorNorthWestResize: 109 case ui::kCursorNorthWestResize:
114 return XC_top_left_corner; 110 return "nw-resize";
115 case ui::kCursorSouthResize: 111 case ui::kCursorSouthResize:
116 return XC_bottom_side; 112 return "s-resize";
117 case ui::kCursorSouthEastResize: 113 case ui::kCursorSouthEastResize:
118 return XC_bottom_right_corner; 114 return "se-resize";
119 case ui::kCursorSouthWestResize: 115 case ui::kCursorSouthWestResize:
120 return XC_bottom_left_corner; 116 return "sw-resize";
121 case ui::kCursorWestResize: 117 case ui::kCursorWestResize:
122 return XC_left_side; 118 return "w-resize";
123 case ui::kCursorNorthSouthResize: 119 case ui::kCursorNorthSouthResize:
124 return XC_sb_v_double_arrow; 120 return "ns-resize";
125 case ui::kCursorEastWestResize: 121 case ui::kCursorEastWestResize:
126 return XC_sb_h_double_arrow; 122 return "ew-resize";
127 case ui::kCursorColumnResize: 123 case ui::kCursorColumnResize:
128 return XC_sb_h_double_arrow; 124 return "col-resize";
129 case ui::kCursorRowResize: 125 case ui::kCursorRowResize:
130 return XC_sb_v_double_arrow; 126 return "row-resize";
127 case ui::kCursorNorthEastSouthWestResize:
128 return "nesw-resize";
129 case ui::kCursorNorthWestSouthEastResize:
130 return "nwse-resize";
131 case ui::kCursorVerticalText:
132 return "vertical-text";
133 case ui::kCursorZoomIn:
134 return "zoom-in";
135 case ui::kCursorZoomOut:
136 return "zoom-out";
137 case ui::kCursorCell:
138 return "cell";
139 case ui::kCursorContextMenu:
140 return "context-menu";
141 case ui::kCursorAlias:
142 return "alias";
143 case ui::kCursorNoDrop:
144 return "no-drop";
145 case ui::kCursorCopy:
146 return "copy";
147 case ui::kCursorNotAllowed:
148 return "not-allowed";
149 case ui::kCursorDndNone:
150 return "dnd-none";
151 case ui::kCursorDndMove:
152 return "dnd-move";
153 case ui::kCursorDndCopy:
154 return "dnd-copy";
155 case ui::kCursorDndLink:
156 return "dnd-link";
131 #endif // defined(OS_CHROMEOS) 157 #endif // defined(OS_CHROMEOS)
132 case ui::kCursorCustom: 158 case ui::kCursorCustom:
133 NOTREACHED(); 159 NOTREACHED();
134 return XC_left_ptr; 160 return "left_ptr";
135 } 161 }
136 NOTREACHED() << "Case not handled for " << native_cursor.native_type(); 162 NOTREACHED() << "Case not handled for " << id;
137 return XC_left_ptr; 163 return "left_ptr";
138 } 164 }
139 165
166 static const struct {
167 const char* css_name;
168 const char* traditional_name;
169 int shape;
170 } kCursorFallbacks[] = {
171 { "pointer", "hand", XC_hand1 },
172 { "progress", "left_ptr_watch", XC_watch },
173 { "wait", nullptr, XC_watch },
174 { "cell", nullptr, XC_plus },
175 { "crosshair", nullptr, XC_cross },
176 { "text", nullptr, XC_xterm },
177 { "not-allowed", "crossed_circle", None },
178 { "grabbing", nullptr, XC_hand2 },
179 { "col-resize", nullptr, XC_sb_h_double_arrow },
180 { "row-resize", nullptr, XC_sb_v_double_arrow},
181 { "n-resize", nullptr, XC_top_side},
182 { "e-resize", nullptr, XC_right_side},
183 { "s-resize", nullptr, XC_bottom_side},
184 { "w-resize", nullptr, XC_left_side},
185 { "ne-resize", nullptr, XC_top_right_corner},
186 { "nw-resize", nullptr, XC_top_left_corner},
187 { "se-resize", nullptr, XC_bottom_right_corner},
188 { "sw-resize", nullptr, XC_bottom_left_corner},
189 { "ew-resize", nullptr, XC_sb_h_double_arrow},
190 { "ns-resize", nullptr, XC_sb_v_double_arrow},
191 { "nesw-resize", "fd_double_arrow", None},
192 { "nwse-resize", "bd_double_arrow", None},
193 };
194
140 } // namespace 195 } // namespace
141 196
142 namespace ui { 197 namespace ui {
143 198
144 CursorLoader* CursorLoader::Create() { 199 CursorLoader* CursorLoader::Create() {
145 return new CursorLoaderX11; 200 return new CursorLoaderX11;
146 } 201 }
147 202
203 CursorLoaderX11::ImageCursor::ImageCursor(XcursorImage* x_image,
204 float scale,
205 display::Display::Rotation rotation)
206 : scale(scale), rotation(rotation) {
207 cursor = CreateReffedCustomXCursor(x_image);
208 }
209
210 CursorLoaderX11::ImageCursor::~ImageCursor() {
211 UnrefCustomXCursor(cursor);
212 }
213
148 CursorLoaderX11::CursorLoaderX11() 214 CursorLoaderX11::CursorLoaderX11()
149 : invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) { 215 : display_(gfx::GetXDisplay()),
150 } 216 invisible_cursor_(CreateInvisibleCursor(), gfx::GetXDisplay()) {}
151 217
152 CursorLoaderX11::~CursorLoaderX11() { 218 CursorLoaderX11::~CursorLoaderX11() {
153 UnloadAll(); 219 UnloadAll();
154 } 220 }
155 221
156 void CursorLoaderX11::LoadImageCursor(int id, 222 void CursorLoaderX11::LoadImageCursor(int id,
157 int resource_id, 223 int resource_id,
158 const gfx::Point& hot) { 224 const gfx::Point& hot) {
159 SkBitmap bitmap; 225 SkBitmap bitmap;
160 gfx::Point hotspot = hot; 226 gfx::Point hotspot = hot;
161 227
162 GetImageCursorBitmap(resource_id, scale(), rotation(), &hotspot, &bitmap); 228 GetImageCursorBitmap(resource_id, scale(), rotation(), &hotspot, &bitmap);
163 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmap, hotspot); 229 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmap, hotspot);
164 cursors_[id] = CreateReffedCustomXCursor(x_image); 230 image_cursors_[id].reset(new ImageCursor(x_image, scale(), rotation()));
165 } 231 }
166 232
167 void CursorLoaderX11::LoadAnimatedCursor(int id, 233 void CursorLoaderX11::LoadAnimatedCursor(int id,
168 int resource_id, 234 int resource_id,
169 const gfx::Point& hot, 235 const gfx::Point& hot,
170 int frame_delay_ms) { 236 int frame_delay_ms) {
171 std::vector<SkBitmap> bitmaps; 237 std::vector<SkBitmap> bitmaps;
172 gfx::Point hotspot = hot; 238 gfx::Point hotspot = hot;
173 239
174 GetAnimatedCursorBitmaps( 240 GetAnimatedCursorBitmaps(resource_id, scale(), rotation(), &hotspot,
175 resource_id, scale(), rotation(), &hotspot, &bitmaps); 241 &bitmaps);
176 242
177 XcursorImages* x_images = XcursorImagesCreate(bitmaps.size()); 243 XcursorImages* x_images = XcursorImagesCreate(bitmaps.size());
178 x_images->nimage = bitmaps.size(); 244 x_images->nimage = bitmaps.size();
179 245
180 for (unsigned int frame = 0; frame < bitmaps.size(); ++frame) { 246 for (unsigned int frame = 0; frame < bitmaps.size(); ++frame) {
181 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmaps[frame], hotspot); 247 XcursorImage* x_image = SkBitmapToXcursorImage(&bitmaps[frame], hotspot);
182 x_image->delay = frame_delay_ms; 248 x_image->delay = frame_delay_ms;
183 x_images->images[frame] = x_image; 249 x_images->images[frame] = x_image;
184 } 250 }
185 251
186 animated_cursors_[id] = std::make_pair( 252 animated_cursors_[id] = std::make_pair(
187 XcursorImagesLoadCursor(gfx::GetXDisplay(), x_images), x_images); 253 XcursorImagesLoadCursor(gfx::GetXDisplay(), x_images), x_images);
188 } 254 }
189 255
190 void CursorLoaderX11::UnloadAll() { 256 void CursorLoaderX11::UnloadAll() {
191 for (ImageCursorMap::const_iterator it = cursors_.begin(); 257 image_cursors_.clear();
192 it != cursors_.end(); ++it)
193 UnrefCustomXCursor(it->second);
194 258
195 // Free animated cursors and images. 259 // Free animated cursors and images.
196 for (AnimatedCursorMap::iterator it = animated_cursors_.begin(); 260 for (const auto& cursor : animated_cursors_) {
197 it != animated_cursors_.end(); ++it) { 261 XcursorImagesDestroy(
198 XcursorImagesDestroy(it->second.second); // also frees individual frames. 262 cursor.second.second); // also frees individual frames.
199 XFreeCursor(gfx::GetXDisplay(), it->second.first); 263 XFreeCursor(gfx::GetXDisplay(), cursor.second.first);
200 } 264 }
201 } 265 }
202 266
203 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) { 267 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) {
204 DCHECK(cursor); 268 DCHECK(cursor);
205 269
206 ::Cursor xcursor; 270 if (*cursor == kCursorNone) {
207 if (IsImageCursor(*cursor)) 271 cursor->SetPlatformCursor(invisible_cursor_.get());
208 xcursor = ImageCursorFromNative(*cursor); 272 return;
209 else if (*cursor == kCursorNone)
210 xcursor = invisible_cursor_.get();
211 else if (*cursor == kCursorCustom)
212 xcursor = cursor->platform();
213 else if (scale() == 1.0f && rotation() == display::Display::ROTATE_0) {
214 xcursor = GetXCursor(CursorShapeFromNative(*cursor));
215 } else {
216 xcursor = ImageCursorFromNative(kCursorPointer);
217 } 273 }
218 274
219 cursor->SetPlatformCursor(xcursor); 275 if (*cursor == kCursorCustom)
276 return;
277
278 cursor->SetPlatformCursor(CursorFromId(cursor->native_type()));
220 } 279 }
221 280
222 const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) { 281 const XcursorImage* CursorLoaderX11::GetXcursorImageForTest(int id) {
223 return test::GetCachedXcursorImage(cursors_[id]); 282 return test::GetCachedXcursorImage(image_cursors_[id]->cursor);
224 } 283 }
225 284
226 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) { 285 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) {
227 int type = native_cursor.native_type(); 286 int type = native_cursor.native_type();
228 return cursors_.count(type) || animated_cursors_.count(type); 287 return image_cursors_.count(type) || animated_cursors_.count(type);
229 } 288 }
230 289
231 ::Cursor CursorLoaderX11::ImageCursorFromNative( 290 ::Cursor CursorLoaderX11::CursorFromId(int id) {
232 gfx::NativeCursor native_cursor) { 291 const char* css_name = CursorCssNameFromId(id);
233 int type = native_cursor.native_type();
234 if (animated_cursors_.count(type))
235 return animated_cursors_[type].first;
236 292
237 ImageCursorMap::iterator find = cursors_.find(type); 293 auto font_it = font_cursors_.find(id);
238 if (find != cursors_.end()) 294 if (font_it != font_cursors_.end())
239 return cursors_[type]; 295 return font_it->second;
240 return GetXCursor(CursorShapeFromNative(native_cursor)); 296 auto image_it = image_cursors_.find(id);
297 if (image_it != image_cursors_.end()) {
298 if (image_it->second->scale == scale() &&
299 image_it->second->rotation == rotation()) {
300 return image_it->second->cursor;
301 } else {
302 image_cursors_.erase(image_it);
303 }
304 }
305
306 // First try to load the cursor directly.
307 ::Cursor cursor = XcursorLibraryLoadCursor(display_, css_name);
sadrul 2016/11/17 16:17:03 When you say 'directly', do you mean like there ca
Tom (Use chromium acct) 2016/11/17 19:17:48 That's right
308 if (cursor == None) {
309 // Try a similar cursor supplied by the native cursor theme.
310 for (const auto& mapping : kCursorFallbacks) {
311 if (strcmp(mapping.css_name, css_name) == 0) {
312 if (mapping.traditional_name)
313 cursor = XcursorLibraryLoadCursor(display_, mapping.traditional_name);
314 if (cursor == None && mapping.shape)
315 cursor = XCreateFontCursor(display_, mapping.shape);
316 }
317 }
318 }
319 if (cursor != None) {
320 font_cursors_[id] = cursor;
321 return cursor;
322 }
323
324 // If the theme is missing the desired cursor, use a chromium-supplied
325 // fallback icon.
326 int resource_id;
327 gfx::Point point;
328 if (ui::GetCursorDataFor(ui::CURSOR_SET_NORMAL, id, scale(), &resource_id,
329 &point)) {
330 LoadImageCursor(id, resource_id, point);
331 return image_cursors_[id]->cursor;
332 }
333
334 // As a last resort, return a left pointer.
335 cursor = XCreateFontCursor(display_, XC_left_ptr);
336 DCHECK(cursor);
337 font_cursors_[id] = cursor;
338 return cursor;
241 } 339 }
242 340
243 } // namespace ui 341 } // namespace ui
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698