| // Copyright (c) 2011 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 "base/logging.h" |
| #include "base/pickle.h" |
| #include "grit/webkit_resources.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" |
| #include "ui/gfx/gdi_util.h" |
| #include "webkit/glue/webcursor.h" |
| |
| using WebKit::WebCursorInfo; |
| |
| static LPCWSTR ToCursorID(WebCursorInfo::Type type) { |
| switch (type) { |
| case WebCursorInfo::TypePointer: |
| return IDC_ARROW; |
| case WebCursorInfo::TypeCross: |
| return IDC_CROSS; |
| case WebCursorInfo::TypeHand: |
| return IDC_HAND; |
| case WebCursorInfo::TypeIBeam: |
| return IDC_IBEAM; |
| case WebCursorInfo::TypeWait: |
| return IDC_WAIT; |
| case WebCursorInfo::TypeHelp: |
| return IDC_HELP; |
| case WebCursorInfo::TypeEastResize: |
| return IDC_SIZEWE; |
| case WebCursorInfo::TypeNorthResize: |
| return IDC_SIZENS; |
| case WebCursorInfo::TypeNorthEastResize: |
| return IDC_SIZENESW; |
| case WebCursorInfo::TypeNorthWestResize: |
| return IDC_SIZENWSE; |
| case WebCursorInfo::TypeSouthResize: |
| return IDC_SIZENS; |
| case WebCursorInfo::TypeSouthEastResize: |
| return IDC_SIZENWSE; |
| case WebCursorInfo::TypeSouthWestResize: |
| return IDC_SIZENESW; |
| case WebCursorInfo::TypeWestResize: |
| return IDC_SIZEWE; |
| case WebCursorInfo::TypeNorthSouthResize: |
| return IDC_SIZENS; |
| case WebCursorInfo::TypeEastWestResize: |
| return IDC_SIZEWE; |
| case WebCursorInfo::TypeNorthEastSouthWestResize: |
| return IDC_SIZENESW; |
| case WebCursorInfo::TypeNorthWestSouthEastResize: |
| return IDC_SIZENWSE; |
| case WebCursorInfo::TypeColumnResize: |
| return MAKEINTRESOURCE(IDC_COLRESIZE); |
| case WebCursorInfo::TypeRowResize: |
| return MAKEINTRESOURCE(IDC_ROWRESIZE); |
| case WebCursorInfo::TypeMiddlePanning: |
| return MAKEINTRESOURCE(IDC_PAN_MIDDLE); |
| case WebCursorInfo::TypeEastPanning: |
| return MAKEINTRESOURCE(IDC_PAN_EAST); |
| case WebCursorInfo::TypeNorthPanning: |
| return MAKEINTRESOURCE(IDC_PAN_NORTH); |
| case WebCursorInfo::TypeNorthEastPanning: |
| return MAKEINTRESOURCE(IDC_PAN_NORTH_EAST); |
| case WebCursorInfo::TypeNorthWestPanning: |
| return MAKEINTRESOURCE(IDC_PAN_NORTH_WEST); |
| case WebCursorInfo::TypeSouthPanning: |
| return MAKEINTRESOURCE(IDC_PAN_SOUTH); |
| case WebCursorInfo::TypeSouthEastPanning: |
| return MAKEINTRESOURCE(IDC_PAN_SOUTH_EAST); |
| case WebCursorInfo::TypeSouthWestPanning: |
| return MAKEINTRESOURCE(IDC_PAN_SOUTH_WEST); |
| case WebCursorInfo::TypeWestPanning: |
| return MAKEINTRESOURCE(IDC_PAN_WEST); |
| case WebCursorInfo::TypeMove: |
| return IDC_SIZEALL; |
| case WebCursorInfo::TypeVerticalText: |
| return MAKEINTRESOURCE(IDC_VERTICALTEXT); |
| case WebCursorInfo::TypeCell: |
| return MAKEINTRESOURCE(IDC_CELL); |
| case WebCursorInfo::TypeContextMenu: |
| return MAKEINTRESOURCE(IDC_ARROW); |
| case WebCursorInfo::TypeAlias: |
| return MAKEINTRESOURCE(IDC_ALIAS); |
| case WebCursorInfo::TypeProgress: |
| return IDC_APPSTARTING; |
| case WebCursorInfo::TypeNoDrop: |
| return IDC_NO; |
| case WebCursorInfo::TypeCopy: |
| return MAKEINTRESOURCE(IDC_COPYCUR); |
| case WebCursorInfo::TypeNone: |
| return IDC_ARROW; |
| case WebCursorInfo::TypeNotAllowed: |
| return IDC_NO; |
| case WebCursorInfo::TypeZoomIn: |
| return MAKEINTRESOURCE(IDC_ZOOMIN); |
| case WebCursorInfo::TypeZoomOut: |
| return MAKEINTRESOURCE(IDC_ZOOMOUT); |
| // TODO(avi): get cursor images for grab/grabbing |
| // http://crbug.com/74699 |
| case WebCursorInfo::TypeGrab: |
| case WebCursorInfo::TypeGrabbing: |
| return IDC_ARROW; |
| } |
| NOTREACHED(); |
| return NULL; |
| } |
| |
| static bool IsSystemCursorID(LPCWSTR cursor_id) { |
| return cursor_id >= IDC_ARROW; // See WinUser.h |
| } |
| |
| static WebCursorInfo::Type ToCursorType(HCURSOR cursor) { |
| static struct { |
| HCURSOR cursor; |
| WebCursorInfo::Type type; |
| } kStandardCursors[] = { |
| { LoadCursor(NULL, IDC_ARROW), WebCursorInfo::TypePointer }, |
| { LoadCursor(NULL, IDC_CROSS), WebCursorInfo::TypeCross }, |
| { LoadCursor(NULL, IDC_HAND), WebCursorInfo::TypeHand }, |
| { LoadCursor(NULL, IDC_IBEAM), WebCursorInfo::TypeIBeam }, |
| { LoadCursor(NULL, IDC_WAIT), WebCursorInfo::TypeWait }, |
| { LoadCursor(NULL, IDC_HELP), WebCursorInfo::TypeHelp }, |
| { LoadCursor(NULL, IDC_SIZENESW), WebCursorInfo::TypeNorthEastResize }, |
| { LoadCursor(NULL, IDC_SIZENWSE), WebCursorInfo::TypeNorthWestResize }, |
| { LoadCursor(NULL, IDC_SIZENS), WebCursorInfo::TypeNorthSouthResize }, |
| { LoadCursor(NULL, IDC_SIZEWE), WebCursorInfo::TypeEastWestResize }, |
| { LoadCursor(NULL, IDC_SIZEALL), WebCursorInfo::TypeMove }, |
| { LoadCursor(NULL, IDC_APPSTARTING), WebCursorInfo::TypeProgress }, |
| { LoadCursor(NULL, IDC_NO), WebCursorInfo::TypeNotAllowed }, |
| }; |
| for (int i = 0; i < arraysize(kStandardCursors); i++) { |
| if (cursor == kStandardCursors[i].cursor) |
| return kStandardCursors[i].type; |
| } |
| return WebCursorInfo::TypeCustom; |
| } |
| |
| HCURSOR WebCursor::GetCursor(HINSTANCE module_handle){ |
| if (!IsCustom()) { |
| const wchar_t* cursor_id = |
| ToCursorID(static_cast<WebCursorInfo::Type>(type_)); |
| |
| if (IsSystemCursorID(cursor_id)) |
| module_handle = NULL; |
| |
| return LoadCursor(module_handle, cursor_id); |
| } |
| |
| if (custom_cursor_) { |
| DCHECK(external_cursor_ == NULL); |
| return custom_cursor_; |
| } |
| |
| if (external_cursor_) |
| return external_cursor_; |
| |
| BITMAPINFO cursor_bitmap_info = {0}; |
| gfx::CreateBitmapHeader( |
| custom_size_.width(), custom_size_.height(), |
| reinterpret_cast<BITMAPINFOHEADER*>(&cursor_bitmap_info)); |
| HDC dc = GetDC(0); |
| HDC workingDC = CreateCompatibleDC(dc); |
| HBITMAP bitmap_handle = CreateDIBSection( |
| dc, &cursor_bitmap_info, DIB_RGB_COLORS, 0, 0, 0); |
| if (!custom_data_.empty()) |
| SetDIBits( |
| 0, bitmap_handle, 0, custom_size_.height(), &custom_data_[0], |
| &cursor_bitmap_info, DIB_RGB_COLORS); |
| |
| HBITMAP old_bitmap = reinterpret_cast<HBITMAP>( |
| SelectObject(workingDC, bitmap_handle)); |
| SetBkMode(workingDC, TRANSPARENT); |
| SelectObject(workingDC, old_bitmap); |
| |
| HBITMAP mask = CreateBitmap( |
| custom_size_.width(), custom_size_.height(), 1, 1, NULL); |
| ICONINFO ii = {0}; |
| ii.fIcon = FALSE; |
| ii.xHotspot = hotspot_.x(); |
| ii.yHotspot = hotspot_.y(); |
| ii.hbmMask = mask; |
| ii.hbmColor = bitmap_handle; |
| |
| custom_cursor_ = CreateIconIndirect(&ii); |
| |
| DeleteObject(mask); |
| DeleteObject(bitmap_handle); |
| DeleteDC(workingDC); |
| ReleaseDC(0, dc); |
| return custom_cursor_; |
| } |
| |
| gfx::NativeCursor WebCursor::GetNativeCursor() { |
| return GetCursor(NULL); |
| } |
| |
| void WebCursor::InitFromExternalCursor(HCURSOR cursor) { |
| WebCursorInfo::Type cursor_type = ToCursorType(cursor); |
| |
| InitFromCursorInfo(WebCursorInfo(cursor_type)); |
| |
| if (cursor_type == WebCursorInfo::TypeCustom) |
| external_cursor_ = cursor; |
| } |
| |
| void WebCursor::InitPlatformData() { |
| external_cursor_ = NULL; |
| custom_cursor_ = NULL; |
| } |
| |
| bool WebCursor::SerializePlatformData(Pickle* pickle) const { |
| // There are some issues with converting certain HCURSORS to bitmaps. The |
| // HCURSOR being a user object can be marshaled as is. |
| // HCURSORs are always 32 bits on Windows, even on 64 bit systems. |
| return pickle->WriteUInt32(reinterpret_cast<uint32>(external_cursor_)); |
| } |
| |
| bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { |
| return pickle->ReadUInt32(iter, reinterpret_cast<uint32*>(&external_cursor_)); |
| } |
| |
| bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { |
| if (!IsCustom()) |
| return true; |
| |
| return (external_cursor_ == other.external_cursor_); |
| } |
| |
| void WebCursor::CopyPlatformData(const WebCursor& other) { |
| external_cursor_ = other.external_cursor_; |
| // The custom_cursor_ member will be initialized to a HCURSOR the next time |
| // the GetCursor member function is invoked on this WebCursor instance. The |
| // cursor is created using the data in the custom_data_ vector. |
| custom_cursor_ = NULL; |
| } |
| |
| void WebCursor::CleanupPlatformData() { |
| external_cursor_ = NULL; |
| |
| if (custom_cursor_) { |
| DestroyIcon(custom_cursor_); |
| custom_cursor_ = NULL; |
| } |
| } |