// 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;
}
}