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