OLD | NEW |
(Empty) | |
| 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. |
| 4 |
| 5 #include "ui/base/cursor/cursor_loader_x11.h" |
| 6 |
| 7 #include <X11/Xlib.h> |
| 8 #include <X11/cursorfont.h> |
| 9 |
| 10 #include "base/logging.h" |
| 11 #include "grit/ui_resources.h" |
| 12 #include "ui/base/cursor/cursor.h" |
| 13 #include "ui/base/resource/resource_bundle.h" |
| 14 #include "ui/base/x/x11_util.h" |
| 15 #include "ui/gfx/image/image.h" |
| 16 #include "ui/gfx/image/image_skia.h" |
| 17 |
| 18 namespace { |
| 19 |
| 20 // Returns X font cursor shape from an Aura cursor. |
| 21 int CursorShapeFromNative(gfx::NativeCursor native_cursor) { |
| 22 switch (native_cursor.native_type()) { |
| 23 case ui::kCursorMiddlePanning: |
| 24 return XC_fleur; |
| 25 case ui::kCursorEastPanning: |
| 26 return XC_sb_right_arrow; |
| 27 case ui::kCursorNorthPanning: |
| 28 return XC_sb_up_arrow; |
| 29 case ui::kCursorNorthEastPanning: |
| 30 return XC_top_right_corner; |
| 31 case ui::kCursorNorthWestPanning: |
| 32 return XC_top_left_corner; |
| 33 case ui::kCursorSouthPanning: |
| 34 return XC_sb_down_arrow; |
| 35 case ui::kCursorSouthEastPanning: |
| 36 return XC_bottom_right_corner; |
| 37 case ui::kCursorSouthWestPanning: |
| 38 return XC_bottom_left_corner; |
| 39 case ui::kCursorWestPanning: |
| 40 return XC_sb_left_arrow; |
| 41 case ui::kCursorNone: |
| 42 case ui::kCursorGrab: |
| 43 case ui::kCursorGrabbing: |
| 44 // TODO(jamescook): Need cursors for these. crbug.com/111650 |
| 45 return XC_left_ptr; |
| 46 |
| 47 case ui::kCursorNull: |
| 48 case ui::kCursorPointer: |
| 49 case ui::kCursorNoDrop: |
| 50 case ui::kCursorNotAllowed: |
| 51 case ui::kCursorCopy: |
| 52 case ui::kCursorMove: |
| 53 case ui::kCursorEastResize: |
| 54 case ui::kCursorNorthResize: |
| 55 case ui::kCursorSouthResize: |
| 56 case ui::kCursorWestResize: |
| 57 case ui::kCursorNorthEastResize: |
| 58 case ui::kCursorNorthWestResize: |
| 59 case ui::kCursorSouthWestResize: |
| 60 case ui::kCursorSouthEastResize: |
| 61 case ui::kCursorIBeam: |
| 62 case ui::kCursorAlias: |
| 63 case ui::kCursorCell: |
| 64 case ui::kCursorContextMenu: |
| 65 case ui::kCursorCross: |
| 66 case ui::kCursorHelp: |
| 67 case ui::kCursorWait: |
| 68 case ui::kCursorNorthSouthResize: |
| 69 case ui::kCursorEastWestResize: |
| 70 case ui::kCursorNorthEastSouthWestResize: |
| 71 case ui::kCursorNorthWestSouthEastResize: |
| 72 case ui::kCursorProgress: |
| 73 case ui::kCursorColumnResize: |
| 74 case ui::kCursorRowResize: |
| 75 case ui::kCursorVerticalText: |
| 76 case ui::kCursorZoomIn: |
| 77 case ui::kCursorZoomOut: |
| 78 NOTREACHED() << "Cursor (" << native_cursor.native_type() << ") should " |
| 79 << "have an image asset."; |
| 80 return XC_left_ptr; |
| 81 case ui::kCursorCustom: |
| 82 NOTREACHED(); |
| 83 return XC_left_ptr; |
| 84 } |
| 85 NOTREACHED(); |
| 86 return XC_left_ptr; |
| 87 } |
| 88 |
| 89 } // namespace |
| 90 |
| 91 namespace ui { |
| 92 |
| 93 CursorLoader* CursorLoader::Create() { |
| 94 return new CursorLoaderX11; |
| 95 } |
| 96 |
| 97 CursorLoaderX11::CursorLoaderX11() { |
| 98 } |
| 99 |
| 100 CursorLoaderX11::~CursorLoaderX11() { |
| 101 UnloadAll(); |
| 102 // Clears XCursorCache. |
| 103 ui::GetXCursor(ui::kCursorClearXCursorCache); |
| 104 } |
| 105 |
| 106 void CursorLoaderX11::LoadImageCursor( |
| 107 int id, int resource_id, const gfx::Point& hot) { |
| 108 const gfx::ImageSkia* image = |
| 109 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); |
| 110 const gfx::ImageSkiaRep& image_rep = image->GetRepresentation( |
| 111 ui::GetScaleFactorFromScale(device_scale_factor())); |
| 112 XcursorImage* x_image = |
| 113 ui::SkBitmapToXcursorImage(&image_rep.sk_bitmap(), hot); |
| 114 cursors_[id] = ui::CreateReffedCustomXCursor(x_image); |
| 115 // |bitmap| is owned by the resource bundle. So we do not need to free it. |
| 116 } |
| 117 |
| 118 void CursorLoaderX11::LoadAnimatedCursor( |
| 119 int id, int resource_id, const gfx::Point& hot, int frame_delay_ms) { |
| 120 const gfx::ImageSkia* image = |
| 121 ui::ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id); |
| 122 const gfx::ImageSkiaRep& image_rep = image->GetRepresentation( |
| 123 ui::GetScaleFactorFromScale(device_scale_factor())); |
| 124 const SkBitmap bitmap = image_rep.sk_bitmap(); |
| 125 DCHECK_EQ(bitmap.config(), SkBitmap::kARGB_8888_Config); |
| 126 int frame_width = bitmap.height(); |
| 127 int frame_height = frame_width; |
| 128 int total_width = bitmap.width(); |
| 129 DCHECK_EQ(total_width % frame_width, 0); |
| 130 int frame_count = total_width / frame_width; |
| 131 DCHECK_GT(frame_count, 0); |
| 132 XcursorImages* x_images = XcursorImagesCreate(frame_count); |
| 133 x_images->nimage = frame_count; |
| 134 bitmap.lockPixels(); |
| 135 unsigned int* pixels = bitmap.getAddr32(0, 0); |
| 136 // Create each frame. |
| 137 for (int i = 0; i < frame_count; ++i) { |
| 138 XcursorImage* x_image = XcursorImageCreate(frame_width, frame_height); |
| 139 for (int j = 0; j < frame_height; ++j) { |
| 140 // Copy j'th row of i'th frame. |
| 141 memcpy(x_image->pixels + j * frame_width, |
| 142 pixels + i * frame_width + j * total_width, |
| 143 frame_width * 4); |
| 144 } |
| 145 x_image->xhot = hot.x(); |
| 146 x_image->yhot = hot.y(); |
| 147 x_image->delay = frame_delay_ms; |
| 148 x_images->images[i] = x_image; |
| 149 } |
| 150 bitmap.unlockPixels(); |
| 151 |
| 152 animated_cursors_[id] = std::make_pair( |
| 153 XcursorImagesLoadCursor(ui::GetXDisplay(), x_images), x_images); |
| 154 // |bitmap| is owned by the resource bundle. So we do not need to free it. |
| 155 } |
| 156 |
| 157 void CursorLoaderX11::UnloadAll() { |
| 158 for (ImageCursorMap::const_iterator it = cursors_.begin(); |
| 159 it != cursors_.end(); ++it) |
| 160 ui::UnrefCustomXCursor(it->second); |
| 161 |
| 162 // Free animated cursors and images. |
| 163 for (AnimatedCursorMap::iterator it = animated_cursors_.begin(); |
| 164 it != animated_cursors_.end(); ++it) { |
| 165 XcursorImagesDestroy(it->second.second); // also frees individual frames. |
| 166 XFreeCursor(ui::GetXDisplay(), it->second.first); |
| 167 } |
| 168 } |
| 169 |
| 170 void CursorLoaderX11::SetPlatformCursor(gfx::NativeCursor* cursor) { |
| 171 DCHECK(cursor); |
| 172 |
| 173 ::Cursor xcursor; |
| 174 if (IsImageCursor(*cursor)) |
| 175 xcursor = ImageCursorFromNative(*cursor); |
| 176 else if (*cursor == ui::kCursorNone) |
| 177 xcursor = ui::GetInvisibleCursor(); |
| 178 else if (*cursor == ui::kCursorCustom) |
| 179 xcursor = cursor->platform(); |
| 180 else if (device_scale_factor() == 1.0f) |
| 181 xcursor = ui::GetXCursor(CursorShapeFromNative(*cursor)); |
| 182 else |
| 183 xcursor = ImageCursorFromNative(ui::kCursorPointer); |
| 184 |
| 185 cursor->SetPlatformCursor(xcursor); |
| 186 } |
| 187 |
| 188 bool CursorLoaderX11::IsImageCursor(gfx::NativeCursor native_cursor) { |
| 189 int type = native_cursor.native_type(); |
| 190 return cursors_.find(type) != cursors_.end() || |
| 191 animated_cursors_.find(type) != animated_cursors_.end(); |
| 192 } |
| 193 |
| 194 ::Cursor CursorLoaderX11::ImageCursorFromNative( |
| 195 gfx::NativeCursor native_cursor) { |
| 196 int type = native_cursor.native_type(); |
| 197 if (animated_cursors_.count(type)) |
| 198 return animated_cursors_[type].first; |
| 199 DCHECK(cursors_.find(type) != cursors_.end()); |
| 200 return cursors_[type]; |
| 201 } |
| 202 |
| 203 } |
OLD | NEW |