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
13using WebKit::WebCursorInfo;
14
15static 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
109static bool IsSystemCursorID(LPCWSTR cursor_id) {
110  return cursor_id >= IDC_ARROW;  // See WinUser.h
111}
112
113static 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
139HCURSOR 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
194gfx::NativeCursor WebCursor::GetNativeCursor() {
195  return GetCursor(NULL);
196}
197
198void 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
207void WebCursor::InitPlatformData() {
208  external_cursor_ = NULL;
209  custom_cursor_ = NULL;
210}
211
212bool 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
219bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) {
220  return pickle->ReadUInt32(iter, reinterpret_cast<uint32*>(&external_cursor_));
221}
222
223bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const {
224  if (!IsCustom())
225    return true;
226
227  return (external_cursor_ == other.external_cursor_);
228}
229
230void 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
238void WebCursor::CleanupPlatformData() {
239  external_cursor_ = NULL;
240
241  if (custom_cursor_) {
242    DestroyIcon(custom_cursor_);
243    custom_cursor_ = NULL;
244  }
245}
246