| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/platform_window/x11/x11_cursor_ozone.h" |
| |
| #include <X11/Xcursor/Xcursor.h> |
| #include <X11/Xlib.h> |
| |
| #include "base/logging.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "ui/base/x/x11_util.h" |
| #include "ui/gfx/geometry/point.h" |
| |
| namespace ui { |
| |
| namespace { |
| |
| // Converts a SKBitmap to unpremul alpha. |
| SkBitmap ConvertSkBitmapToUnpremul(const SkBitmap& bitmap) { |
| DCHECK_NE(bitmap.alphaType(), kUnpremul_SkAlphaType); |
| |
| SkImageInfo image_info = SkImageInfo::MakeN32(bitmap.width(), bitmap.height(), |
| kUnpremul_SkAlphaType); |
| SkBitmap converted_bitmap; |
| converted_bitmap.allocPixels(image_info); |
| bitmap.readPixels(image_info, converted_bitmap.getPixels(), |
| image_info.minRowBytes(), 0, 0); |
| |
| return converted_bitmap; |
| } |
| |
| // Creates an XCursorImage for cursor bitmap. |
| XcursorImage* CreateXCursorImage(const SkBitmap& bitmap, |
| const gfx::Point& hotspot) { |
| // X11 expects bitmap with unpremul alpha. If bitmap is premul then convert, |
| // otherwise semi-transparent parts of cursor will look strange. |
| if (bitmap.alphaType() != kUnpremul_SkAlphaType) { |
| SkBitmap converted_bitmap = ConvertSkBitmapToUnpremul(bitmap); |
| return SkBitmapToXcursorImage(&converted_bitmap, hotspot); |
| } else { |
| return SkBitmapToXcursorImage(&bitmap, hotspot); |
| } |
| } |
| |
| } // namespace |
| |
| X11CursorOzone::X11CursorOzone(const SkBitmap& bitmap, |
| const gfx::Point& hotspot) { |
| XcursorImage* image = CreateXCursorImage(bitmap, hotspot); |
| xcursor_ = XcursorImageLoadCursor(gfx::GetXDisplay(), image); |
| XcursorImageDestroy(image); |
| } |
| |
| X11CursorOzone::X11CursorOzone(const std::vector<SkBitmap>& bitmaps, |
| const gfx::Point& hotspot, |
| int frame_delay_ms) { |
| // Initialize an XCursorImage for each frame, store all of them in |
| // XCursorImages and load the cursor from that. |
| XcursorImages* images = XcursorImagesCreate(bitmaps.size()); |
| images->nimage = bitmaps.size(); |
| for (size_t frame = 0; frame < bitmaps.size(); ++frame) { |
| XcursorImage* x_image = CreateXCursorImage(bitmaps[frame], hotspot); |
| x_image->delay = frame_delay_ms; |
| images->images[frame] = x_image; |
| } |
| |
| xcursor_ = XcursorImagesLoadCursor(gfx::GetXDisplay(), images); |
| XcursorImagesDestroy(images); |
| } |
| |
| scoped_refptr<X11CursorOzone> X11CursorOzone::CreateInvisible() { |
| scoped_refptr<X11CursorOzone> invisible_ = new X11CursorOzone(); |
| invisible_->xcursor_ = CreateInvisibleCursor(); |
| return invisible_; |
| } |
| |
| X11CursorOzone::X11CursorOzone() {} |
| |
| X11CursorOzone::~X11CursorOzone() { |
| XFreeCursor(gfx::GetXDisplay(), xcursor_); |
| } |
| |
| } // namespace ui |