1 // Copyright (c) 2011 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 "base/logging.h" 6 #include "base/pickle.h" 7 #include "grit/webkit_resources.h" 8 #include "third_party/skia/include/core/SkBitmap.h" 9 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h" 10 #include "ui/gfx/gdi_util.h" 11 #include "webkit/glue/webcursor.h" 12 13 using WebKit::WebCursorInfo; 14 15 static LPCWSTR ToCursorID(WebCursorInfo::Type type) { 16 switch (type) { 17 case WebCursorInfo::TypePointer: 18 return IDC_ARROW; 19 case WebCursorInfo::TypeCross: 20 return IDC_CROSS; 21 case WebCursorInfo::TypeHand: 22 return IDC_HAND; 23 case WebCursorInfo::TypeIBeam: 24 return IDC_IBEAM; 25 case WebCursorInfo::TypeWait: 26 return IDC_WAIT; 27 case WebCursorInfo::TypeHelp: 28 return IDC_HELP; 29 case WebCursorInfo::TypeEastResize: 30 return IDC_SIZEWE; 31 case WebCursorInfo::TypeNorthResize: 32 return IDC_SIZENS; 33 case WebCursorInfo::TypeNorthEastResize: 34 return IDC_SIZENESW; 35 case WebCursorInfo::TypeNorthWestResize: 36 return IDC_SIZENWSE; 37 case WebCursorInfo::TypeSouthResize: 38 return IDC_SIZENS; 39 case WebCursorInfo::TypeSouthEastResize: 40 return IDC_SIZENWSE; 41 case WebCursorInfo::TypeSouthWestResize: 42 return IDC_SIZENESW; 43 case WebCursorInfo::TypeWestResize: 44 return IDC_SIZEWE; 45 case WebCursorInfo::TypeNorthSouthResize: 46 return IDC_SIZENS; 47 case WebCursorInfo::TypeEastWestResize: 48 return IDC_SIZEWE; 49 case WebCursorInfo::TypeNorthEastSouthWestResize: 50 return IDC_SIZENESW; 51 case WebCursorInfo::TypeNorthWestSouthEastResize: 52 return IDC_SIZENWSE; 53 case WebCursorInfo::TypeColumnResize: 54 return MAKEINTRESOURCE(IDC_COLRESIZE); 55 case WebCursorInfo::TypeRowResize: 56 return MAKEINTRESOURCE(IDC_ROWRESIZE); 57 case WebCursorInfo::TypeMiddlePanning: 58 return MAKEINTRESOURCE(IDC_PAN_MIDDLE); 59 case WebCursorInfo::TypeEastPanning: 60 return MAKEINTRESOURCE(IDC_PAN_EAST); 61 case WebCursorInfo::TypeNorthPanning: 62 return MAKEINTRESOURCE(IDC_PAN_NORTH); 63 case WebCursorInfo::TypeNorthEastPanning: 64 return MAKEINTRESOURCE(IDC_PAN_NORTH_EAST); 65 case WebCursorInfo::TypeNorthWestPanning: 66 return MAKEINTRESOURCE(IDC_PAN_NORTH_WEST); 67 case WebCursorInfo::TypeSouthPanning: 68 return MAKEINTRESOURCE(IDC_PAN_SOUTH); 69 case WebCursorInfo::TypeSouthEastPanning: 70 return MAKEINTRESOURCE(IDC_PAN_SOUTH_EAST); 71 case WebCursorInfo::TypeSouthWestPanning: 72 return MAKEINTRESOURCE(IDC_PAN_SOUTH_WEST); 73 case WebCursorInfo::TypeWestPanning: 74 return MAKEINTRESOURCE(IDC_PAN_WEST); 75 case WebCursorInfo::TypeMove: 76 return IDC_SIZEALL; 77 case WebCursorInfo::TypeVerticalText: 78 return MAKEINTRESOURCE(IDC_VERTICALTEXT); 79 case WebCursorInfo::TypeCell: 80 return MAKEINTRESOURCE(IDC_CELL); 81 case WebCursorInfo::TypeContextMenu: 82 return MAKEINTRESOURCE(IDC_ARROW); 83 case WebCursorInfo::TypeAlias: 84 return MAKEINTRESOURCE(IDC_ALIAS); 85 case WebCursorInfo::TypeProgress: 86 return IDC_APPSTARTING; 87 case WebCursorInfo::TypeNoDrop: 88 return IDC_NO; 89 case WebCursorInfo::TypeCopy: 90 return MAKEINTRESOURCE(IDC_COPYCUR); 91 case WebCursorInfo::TypeNone: 92 return IDC_ARROW; 93 case WebCursorInfo::TypeNotAllowed: 94 return IDC_NO; 95 case WebCursorInfo::TypeZoomIn: 96 return MAKEINTRESOURCE(IDC_ZOOMIN); 97 case WebCursorInfo::TypeZoomOut: 98 return MAKEINTRESOURCE(IDC_ZOOMOUT); 99 // TODO(avi): get cursor images for grab/grabbing 100 // http://crbug.com/74699 101 case WebCursorInfo::TypeGrab: 102 case WebCursorInfo::TypeGrabbing: 103 return IDC_ARROW; 104 } 105 NOTREACHED(); 106 return NULL; 107 } 108 109 static bool IsSystemCursorID(LPCWSTR cursor_id) { 110 return cursor_id >= IDC_ARROW; // See WinUser.h 111 } 112 113 static WebCursorInfo::Type ToCursorType(HCURSOR cursor) { 114 static struct { 115 HCURSOR cursor; 116 WebCursorInfo::Type type; 117 } kStandardCursors[] = { 118 { LoadCursor(NULL, IDC_ARROW), WebCursorInfo::TypePointer }, 119 { LoadCursor(NULL, IDC_CROSS), WebCursorInfo::TypeCross }, 120 { LoadCursor(NULL, IDC_HAND), WebCursorInfo::TypeHand }, 121 { LoadCursor(NULL, IDC_IBEAM), WebCursorInfo::TypeIBeam }, 122 { LoadCursor(NULL, IDC_WAIT), WebCursorInfo::TypeWait }, 123 { LoadCursor(NULL, IDC_HELP), WebCursorInfo::TypeHelp }, 124 { LoadCursor(NULL, IDC_SIZENESW), WebCursorInfo::TypeNorthEastResize }, 125 { LoadCursor(NULL, IDC_SIZENWSE), WebCursorInfo::TypeNorthWestResize }, 126 { LoadCursor(NULL, IDC_SIZENS), WebCursorInfo::TypeNorthSouthResize }, 127 { LoadCursor(NULL, IDC_SIZEWE), WebCursorInfo::TypeEastWestResize }, 128 { LoadCursor(NULL, IDC_SIZEALL), WebCursorInfo::TypeMove }, 129 { LoadCursor(NULL, IDC_APPSTARTING), WebCursorInfo::TypeProgress }, 130 { LoadCursor(NULL, IDC_NO), WebCursorInfo::TypeNotAllowed }, 131 }; 132 for (int i = 0; i < arraysize(kStandardCursors); i++) { 133 if (cursor == kStandardCursors[i].cursor) 134 return kStandardCursors[i].type; 135 } 136 return WebCursorInfo::TypeCustom; 137 } 138 139 HCURSOR WebCursor::GetCursor(HINSTANCE module_handle){ 140 if (!IsCustom()) { 141 const wchar_t* cursor_id = 142 ToCursorID(static_cast<WebCursorInfo::Type>(type_)); 143 144 if (IsSystemCursorID(cursor_id)) 145 module_handle = NULL; 146 147 return LoadCursor(module_handle, cursor_id); 148 } 149 150 if (custom_cursor_) { 151 DCHECK(external_cursor_ == NULL); 152 return custom_cursor_; 153 } 154 155 if (external_cursor_) 156 return external_cursor_; 157 158 BITMAPINFO cursor_bitmap_info = {0}; 159 gfx::CreateBitmapHeader( 160 custom_size_.width(), custom_size_.height(), 161 reinterpret_cast<BITMAPINFOHEADER*>(&cursor_bitmap_info)); 162 HDC dc = GetDC(0); 163 HDC workingDC = CreateCompatibleDC(dc); 164 HBITMAP bitmap_handle = CreateDIBSection( 165 dc, &cursor_bitmap_info, DIB_RGB_COLORS, 0, 0, 0); 166 if (!custom_data_.empty()) 167 SetDIBits( 168 0, bitmap_handle, 0, custom_size_.height(), &custom_data_[0], 169 &cursor_bitmap_info, DIB_RGB_COLORS); 170 171 HBITMAP old_bitmap = reinterpret_cast<HBITMAP>( 172 SelectObject(workingDC, bitmap_handle)); 173 SetBkMode(workingDC, TRANSPARENT); 174 SelectObject(workingDC, old_bitmap); 175 176 HBITMAP mask = CreateBitmap( 177 custom_size_.width(), custom_size_.height(), 1, 1, NULL); 178 ICONINFO ii = {0}; 179 ii.fIcon = FALSE; 180 ii.xHotspot = hotspot_.x(); 181 ii.yHotspot = hotspot_.y(); 182 ii.hbmMask = mask; 183 ii.hbmColor = bitmap_handle; 184 185 custom_cursor_ = CreateIconIndirect(&ii); 186 187 DeleteObject(mask); 188 DeleteObject(bitmap_handle); 189 DeleteDC(workingDC); 190 ReleaseDC(0, dc); 191 return custom_cursor_; 192 } 193 194 gfx::NativeCursor WebCursor::GetNativeCursor() { 195 return GetCursor(NULL); 196 } 197 198 void WebCursor::InitFromExternalCursor(HCURSOR cursor) { 199 WebCursorInfo::Type cursor_type = ToCursorType(cursor); 200 201 InitFromCursorInfo(WebCursorInfo(cursor_type)); 202 203 if (cursor_type == WebCursorInfo::TypeCustom) 204 external_cursor_ = cursor; 205 } 206 207 void WebCursor::InitPlatformData() { 208 external_cursor_ = NULL; 209 custom_cursor_ = NULL; 210 } 211 212 bool WebCursor::SerializePlatformData(Pickle* pickle) const { 213 // There are some issues with converting certain HCURSORS to bitmaps. The 214 // HCURSOR being a user object can be marshaled as is. 215 // HCURSORs are always 32 bits on Windows, even on 64 bit systems. 216 return pickle->WriteUInt32(reinterpret_cast<uint32>(external_cursor_)); 217 } 218 219 bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { 220 return pickle->ReadUInt32(iter, reinterpret_cast<uint32*>(&external_cursor_)); 221 } 222 223 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { 224 if (!IsCustom()) 225 return true; 226 227 return (external_cursor_ == other.external_cursor_); 228 } 229 230 void WebCursor::CopyPlatformData(const WebCursor& other) { 231 external_cursor_ = other.external_cursor_; 232 // The custom_cursor_ member will be initialized to a HCURSOR the next time 233 // the GetCursor member function is invoked on this WebCursor instance. The 234 // cursor is created using the data in the custom_data_ vector. 235 custom_cursor_ = NULL; 236 } 237 238 void WebCursor::CleanupPlatformData() { 239 external_cursor_ = NULL; 240 241 if (custom_cursor_) { 242 DestroyIcon(custom_cursor_); 243 custom_cursor_ = NULL; 244 } 245 } 246