1// Copyright (c) 2006-2008 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 "webkit/glue/webcursor.h"
6
7#include "base/logging.h"
8#include "base/pickle.h"
9#include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
10#include "third_party/WebKit/Source/WebKit/chromium/public/WebImage.h"
11
12using WebKit::WebCursorInfo;
13using WebKit::WebImage;
14
15static const int kMaxCursorDimension = 1024;
16
17WebCursor::WebCursor()
18    : type_(WebCursorInfo::TypePointer) {
19  InitPlatformData();
20}
21
22WebCursor::WebCursor(const WebCursorInfo& cursor_info)
23    : type_(WebCursorInfo::TypePointer) {
24  InitPlatformData();
25  InitFromCursorInfo(cursor_info);
26}
27
28WebCursor::~WebCursor() {
29  Clear();
30}
31
32WebCursor::WebCursor(const WebCursor& other) {
33  InitPlatformData();
34  Copy(other);
35}
36
37const WebCursor& WebCursor::operator=(const WebCursor& other) {
38  if (this == &other)
39    return *this;
40
41  Clear();
42  Copy(other);
43  return *this;
44}
45
46void WebCursor::InitFromCursorInfo(const WebCursorInfo& cursor_info) {
47  Clear();
48
49#if defined(OS_WIN)
50  if (cursor_info.externalHandle) {
51    InitFromExternalCursor(cursor_info.externalHandle);
52    return;
53  }
54#endif
55
56  type_ = cursor_info.type;
57  hotspot_ = cursor_info.hotSpot;
58  if (IsCustom())
59    SetCustomData(cursor_info.customImage);
60  ClampHotspot();
61}
62
63void WebCursor::GetCursorInfo(WebCursorInfo* cursor_info) const {
64  cursor_info->type = static_cast<WebCursorInfo::Type>(type_);
65  cursor_info->hotSpot = hotspot_;
66  ImageFromCustomData(&cursor_info->customImage);
67
68#if defined(OS_WIN)
69  cursor_info->externalHandle = external_cursor_;
70#endif
71}
72
73bool WebCursor::Deserialize(const Pickle* pickle, void** iter) {
74  int type, hotspot_x, hotspot_y, size_x, size_y, data_len;
75
76  const char* data;
77
78  // Leave |this| unmodified unless we are going to return success.
79  if (!pickle->ReadInt(iter, &type) ||
80      !pickle->ReadInt(iter, &hotspot_x) ||
81      !pickle->ReadInt(iter, &hotspot_y) ||
82      !pickle->ReadLength(iter, &size_x) ||
83      !pickle->ReadLength(iter, &size_y) ||
84      !pickle->ReadData(iter, &data, &data_len))
85    return false;
86
87  // Ensure the size is sane, and there is enough data.
88  if (size_x > kMaxCursorDimension ||
89      size_y > kMaxCursorDimension)
90    return false;
91
92  type_ = type;
93
94  if (type == WebCursorInfo::TypeCustom) {
95    if (size_x > 0 && size_y > 0) {
96      // The * 4 is because the expected format is an array of RGBA pixel
97      // values.
98      if (size_x * size_y * 4 > data_len)
99        return false;
100
101      hotspot_.set_x(hotspot_x);
102      hotspot_.set_y(hotspot_y);
103      custom_size_.set_width(size_x);
104      custom_size_.set_height(size_y);
105      ClampHotspot();
106
107      custom_data_.clear();
108      if (data_len > 0) {
109        custom_data_.resize(data_len);
110        memcpy(&custom_data_[0], data, data_len);
111      }
112    }
113  }
114  return DeserializePlatformData(pickle, iter);
115}
116
117bool WebCursor::Serialize(Pickle* pickle) const {
118  if (!pickle->WriteInt(type_) ||
119      !pickle->WriteInt(hotspot_.x()) ||
120      !pickle->WriteInt(hotspot_.y()) ||
121      !pickle->WriteInt(custom_size_.width()) ||
122      !pickle->WriteInt(custom_size_.height()))
123    return false;
124
125  const char* data = NULL;
126  if (!custom_data_.empty())
127    data = &custom_data_[0];
128  if (!pickle->WriteData(data, custom_data_.size()))
129    return false;
130
131  return SerializePlatformData(pickle);
132}
133
134bool WebCursor::IsCustom() const {
135  return type_ == WebCursorInfo::TypeCustom;
136}
137
138bool WebCursor::IsEqual(const WebCursor& other) const {
139  if (type_ != other.type_)
140    return false;
141
142  if (!IsPlatformDataEqual(other))
143    return false;
144
145  return hotspot_ == other.hotspot_ &&
146         custom_size_ == other.custom_size_ &&
147         custom_data_ == other.custom_data_;
148}
149
150void WebCursor::Clear() {
151  type_ = WebCursorInfo::TypePointer;
152  hotspot_.set_x(0);
153  hotspot_.set_y(0);
154  custom_size_.set_width(0);
155  custom_size_.set_height(0);
156  custom_data_.clear();
157  CleanupPlatformData();
158}
159
160void WebCursor::Copy(const WebCursor& other) {
161  type_ = other.type_;
162  hotspot_ = other.hotspot_;
163  custom_size_ = other.custom_size_;
164  custom_data_ = other.custom_data_;
165  CopyPlatformData(other);
166}
167
168#if WEBKIT_USING_SKIA
169// The WEBKIT_USING_CG implementation is in webcursor_mac.mm.
170void WebCursor::SetCustomData(const WebImage& image) {
171  if (image.isNull())
172    return;
173
174  // Fill custom_data_ directly with the NativeImage pixels.
175  const SkBitmap& bitmap = image.getSkBitmap();
176  SkAutoLockPixels bitmap_lock(bitmap);
177  custom_data_.resize(bitmap.getSize());
178  if (!custom_data_.empty())
179    memcpy(&custom_data_[0], bitmap.getPixels(), bitmap.getSize());
180  custom_size_.set_width(bitmap.width());
181  custom_size_.set_height(bitmap.height());
182}
183
184void WebCursor::ImageFromCustomData(WebImage* image) const {
185  if (custom_data_.empty())
186    return;
187
188  SkBitmap bitmap;
189  bitmap.setConfig(SkBitmap::kARGB_8888_Config,
190                   custom_size_.width(),
191                   custom_size_.height());
192  if (!bitmap.allocPixels())
193    return;
194  memcpy(bitmap.getPixels(), &custom_data_[0], custom_data_.size());
195
196  image->assign(bitmap);
197}
198#endif
199
200void WebCursor::ClampHotspot() {
201  if (!IsCustom())
202    return;
203
204  // Clamp the hotspot to the custom image's dimensions.
205  hotspot_.set_x(std::max(0,
206                          std::min(custom_size_.width() - 1, hotspot_.x())));
207  hotspot_.set_y(std::max(0,
208                          std::min(custom_size_.height() - 1, hotspot_.y())));
209}
210