e9e27f948d235321beff71061e2d0bd575171be1
[platform/framework/web/crosswalk.git] / src / content / common / cursors / webcursor.cc
1 // Copyright (c) 2012 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 "content/common/cursors/webcursor.h"
6
7 #include "base/logging.h"
8 #include "base/pickle.h"
9 #include "third_party/WebKit/public/platform/WebImage.h"
10
11 using blink::WebCursorInfo;
12
13 static const int kMaxCursorDimension = 1024;
14
15 namespace content {
16
17 WebCursor::WebCursor()
18     : type_(WebCursorInfo::TypePointer),
19       custom_scale_(1) {
20 #if defined(OS_WIN)
21   external_cursor_ = NULL;
22 #endif
23   InitPlatformData();
24 }
25
26 WebCursor::WebCursor(const CursorInfo& cursor_info)
27     : type_(WebCursorInfo::TypePointer) {
28 #if defined(OS_WIN)
29   external_cursor_ = NULL;
30 #endif
31   InitPlatformData();
32   InitFromCursorInfo(cursor_info);
33 }
34
35 WebCursor::~WebCursor() {
36   Clear();
37 }
38
39 WebCursor::WebCursor(const WebCursor& other) {
40   InitPlatformData();
41   Copy(other);
42 }
43
44 const WebCursor& WebCursor::operator=(const WebCursor& other) {
45   if (this == &other)
46     return *this;
47
48   Clear();
49   Copy(other);
50   return *this;
51 }
52
53 void WebCursor::InitFromCursorInfo(const CursorInfo& cursor_info) {
54   Clear();
55
56 #if defined(OS_WIN)
57   if (cursor_info.external_handle) {
58     InitFromExternalCursor(cursor_info.external_handle);
59     return;
60   }
61 #endif
62
63   type_ = cursor_info.type;
64   hotspot_ = cursor_info.hotspot;
65   if (IsCustom())
66     SetCustomData(cursor_info.custom_image);
67   custom_scale_ = cursor_info.image_scale_factor;
68   CHECK(custom_scale_ > 0);
69   ClampHotspot();
70 }
71
72 void WebCursor::GetCursorInfo(CursorInfo* cursor_info) const {
73   cursor_info->type = static_cast<WebCursorInfo::Type>(type_);
74   cursor_info->hotspot = hotspot_;
75   ImageFromCustomData(&cursor_info->custom_image);
76   cursor_info->image_scale_factor = custom_scale_;
77
78 #if defined(OS_WIN)
79   cursor_info->external_handle = external_cursor_;
80 #endif
81 }
82
83 bool WebCursor::Deserialize(PickleIterator* iter) {
84   int type, hotspot_x, hotspot_y, size_x, size_y, data_len;
85   float scale;
86   const char* data;
87
88   // Leave |this| unmodified unless we are going to return success.
89   if (!iter->ReadInt(&type) ||
90       !iter->ReadInt(&hotspot_x) ||
91       !iter->ReadInt(&hotspot_y) ||
92       !iter->ReadLength(&size_x) ||
93       !iter->ReadLength(&size_y) ||
94       !iter->ReadFloat(&scale) ||
95       !iter->ReadData(&data, &data_len))
96     return false;
97
98   // Ensure the size is sane, and there is enough data.
99   if (size_x > kMaxCursorDimension ||
100       size_y > kMaxCursorDimension)
101     return false;
102
103   // Ensure scale isn't ridiculous, and the scaled image size is still sane.
104   if (scale < 0.01 || scale > 100 ||
105       size_x / scale > kMaxCursorDimension ||
106       size_y / scale > kMaxCursorDimension)
107     return false;
108
109   type_ = type;
110
111   if (type == WebCursorInfo::TypeCustom) {
112     if (size_x > 0 && size_y > 0) {
113       // The * 4 is because the expected format is an array of RGBA pixel
114       // values.
115       if (size_x * size_y * 4 > data_len)
116         return false;
117
118       hotspot_.set_x(hotspot_x);
119       hotspot_.set_y(hotspot_y);
120       custom_size_.set_width(size_x);
121       custom_size_.set_height(size_y);
122       custom_scale_ = scale;
123       ClampHotspot();
124
125       custom_data_.clear();
126       if (data_len > 0) {
127         custom_data_.resize(data_len);
128         memcpy(&custom_data_[0], data, data_len);
129       }
130     }
131   }
132   return DeserializePlatformData(iter);
133 }
134
135 bool WebCursor::Serialize(Pickle* pickle) const {
136   if (!pickle->WriteInt(type_) ||
137       !pickle->WriteInt(hotspot_.x()) ||
138       !pickle->WriteInt(hotspot_.y()) ||
139       !pickle->WriteInt(custom_size_.width()) ||
140       !pickle->WriteInt(custom_size_.height()) ||
141       !pickle->WriteFloat(custom_scale_))
142     return false;
143
144   const char* data = NULL;
145   if (!custom_data_.empty())
146     data = &custom_data_[0];
147   if (!pickle->WriteData(data, custom_data_.size()))
148     return false;
149
150   return SerializePlatformData(pickle);
151 }
152
153 bool WebCursor::IsCustom() const {
154   return type_ == WebCursorInfo::TypeCustom;
155 }
156
157 bool WebCursor::IsEqual(const WebCursor& other) const {
158   if (type_ != other.type_)
159     return false;
160
161   if (!IsPlatformDataEqual(other))
162     return false;
163
164   return hotspot_ == other.hotspot_ &&
165          custom_size_ == other.custom_size_ &&
166          custom_scale_ == other.custom_scale_ &&
167          custom_data_ == other.custom_data_;
168 }
169
170 #if defined(OS_WIN)
171
172 static WebCursorInfo::Type ToCursorType(HCURSOR cursor) {
173   static struct {
174     HCURSOR cursor;
175     WebCursorInfo::Type type;
176   } kStandardCursors[] = {
177     { LoadCursor(NULL, IDC_ARROW),       WebCursorInfo::TypePointer },
178     { LoadCursor(NULL, IDC_CROSS),       WebCursorInfo::TypeCross },
179     { LoadCursor(NULL, IDC_HAND),        WebCursorInfo::TypeHand },
180     { LoadCursor(NULL, IDC_IBEAM),       WebCursorInfo::TypeIBeam },
181     { LoadCursor(NULL, IDC_WAIT),        WebCursorInfo::TypeWait },
182     { LoadCursor(NULL, IDC_HELP),        WebCursorInfo::TypeHelp },
183     { LoadCursor(NULL, IDC_SIZENESW),    WebCursorInfo::TypeNorthEastResize },
184     { LoadCursor(NULL, IDC_SIZENWSE),    WebCursorInfo::TypeNorthWestResize },
185     { LoadCursor(NULL, IDC_SIZENS),      WebCursorInfo::TypeNorthSouthResize },
186     { LoadCursor(NULL, IDC_SIZEWE),      WebCursorInfo::TypeEastWestResize },
187     { LoadCursor(NULL, IDC_SIZEALL),     WebCursorInfo::TypeMove },
188     { LoadCursor(NULL, IDC_APPSTARTING), WebCursorInfo::TypeProgress },
189     { LoadCursor(NULL, IDC_NO),          WebCursorInfo::TypeNotAllowed },
190   };
191   for (int i = 0; i < arraysize(kStandardCursors); ++i) {
192     if (cursor == kStandardCursors[i].cursor)
193       return kStandardCursors[i].type;
194   }
195   return WebCursorInfo::TypeCustom;
196 }
197
198 void WebCursor::InitFromExternalCursor(HCURSOR cursor) {
199   WebCursorInfo::Type cursor_type = ToCursorType(cursor);
200
201   InitFromCursorInfo(CursorInfo(cursor_type));
202
203   if (cursor_type == WebCursorInfo::TypeCustom)
204     external_cursor_ = cursor;
205 }
206
207 #endif  // defined(OS_WIN)
208
209 void WebCursor::Clear() {
210   type_ = WebCursorInfo::TypePointer;
211   hotspot_.set_x(0);
212   hotspot_.set_y(0);
213   custom_size_.set_width(0);
214   custom_size_.set_height(0);
215   custom_scale_ = 1;
216   custom_data_.clear();
217   CleanupPlatformData();
218 }
219
220 void WebCursor::Copy(const WebCursor& other) {
221   type_ = other.type_;
222   hotspot_ = other.hotspot_;
223   custom_size_ = other.custom_size_;
224   custom_scale_ = other.custom_scale_;
225   custom_data_ = other.custom_data_;
226   CopyPlatformData(other);
227 }
228
229 void WebCursor::SetCustomData(const SkBitmap& bitmap) {
230   if (bitmap.empty())
231     return;
232
233   // Fill custom_data_ directly with the NativeImage pixels.
234   SkAutoLockPixels bitmap_lock(bitmap);
235   custom_data_.resize(bitmap.getSize());
236   if (!custom_data_.empty())
237     memcpy(&custom_data_[0], bitmap.getPixels(), bitmap.getSize());
238   custom_size_.set_width(bitmap.width());
239   custom_size_.set_height(bitmap.height());
240 }
241
242 void WebCursor::ImageFromCustomData(SkBitmap* image) const {
243   if (custom_data_.empty())
244     return;
245
246   if (!image->allocN32Pixels(custom_size_.width(), custom_size_.height()))
247     return;
248   memcpy(image->getPixels(), &custom_data_[0], custom_data_.size());
249 }
250
251 void WebCursor::ClampHotspot() {
252   if (!IsCustom())
253     return;
254
255   // Clamp the hotspot to the custom image's dimensions.
256   hotspot_.set_x(std::max(0,
257                           std::min(custom_size_.width() - 1, hotspot_.x())));
258   hotspot_.set_y(std::max(0,
259                           std::min(custom_size_.height() - 1, hotspot_.y())));
260 }
261
262 }  // namespace content