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.
5 #include "webkit/common/cursors/webcursor.h"
7 #include "base/logging.h"
8 #include "base/pickle.h"
9 #include "third_party/WebKit/public/platform/WebImage.h"
11 using blink::WebCursorInfo
;
13 static const int kMaxCursorDimension
= 1024;
15 WebCursor::WebCursor()
16 : type_(WebCursorInfo::TypePointer
),
19 external_cursor_
= NULL
;
24 WebCursor::WebCursor(const CursorInfo
& cursor_info
)
25 : type_(WebCursorInfo::TypePointer
) {
27 external_cursor_
= NULL
;
30 InitFromCursorInfo(cursor_info
);
33 WebCursor::~WebCursor() {
37 WebCursor::WebCursor(const WebCursor
& other
) {
42 const WebCursor
& WebCursor::operator=(const WebCursor
& other
) {
51 void WebCursor::InitFromCursorInfo(const CursorInfo
& cursor_info
) {
55 if (cursor_info
.external_handle
) {
56 InitFromExternalCursor(cursor_info
.external_handle
);
61 type_
= cursor_info
.type
;
62 hotspot_
= cursor_info
.hotspot
;
64 SetCustomData(cursor_info
.custom_image
);
65 custom_scale_
= cursor_info
.image_scale_factor
;
66 CHECK(custom_scale_
> 0);
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_
;
77 cursor_info
->external_handle
= external_cursor_
;
81 bool WebCursor::Deserialize(PickleIterator
* iter
) {
82 int type
, hotspot_x
, hotspot_y
, size_x
, size_y
, data_len
;
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
))
96 // Ensure the size is sane, and there is enough data.
97 if (size_x
> kMaxCursorDimension
||
98 size_y
> kMaxCursorDimension
)
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
)
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
113 if (size_x
* size_y
* 4 > data_len
)
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
;
123 custom_data_
.clear();
125 custom_data_
.resize(data_len
);
126 memcpy(&custom_data_
[0], data
, data_len
);
130 return DeserializePlatformData(iter
);
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_
))
142 const char* data
= NULL
;
143 if (!custom_data_
.empty())
144 data
= &custom_data_
[0];
145 if (!pickle
->WriteData(data
, custom_data_
.size()))
148 return SerializePlatformData(pickle
);
151 bool WebCursor::IsCustom() const {
152 return type_
== WebCursorInfo::TypeCustom
;
155 bool WebCursor::IsEqual(const WebCursor
& other
) const {
156 if (type_
!= other
.type_
)
159 if (!IsPlatformDataEqual(other
))
162 return hotspot_
== other
.hotspot_
&&
163 custom_size_
== other
.custom_size_
&&
164 custom_scale_
== other
.custom_scale_
&&
165 custom_data_
== other
.custom_data_
;
170 static WebCursorInfo::Type
ToCursorType(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
},
189 for (int i
= 0; i
< arraysize(kStandardCursors
); ++i
) {
190 if (cursor
== kStandardCursors
[i
].cursor
)
191 return kStandardCursors
[i
].type
;
193 return WebCursorInfo::TypeCustom
;
196 void WebCursor::InitFromExternalCursor(HCURSOR cursor
) {
197 WebCursorInfo::Type cursor_type
= ToCursorType(cursor
);
199 InitFromCursorInfo(CursorInfo(cursor_type
));
201 if (cursor_type
== WebCursorInfo::TypeCustom
)
202 external_cursor_
= cursor
;
205 #endif // defined(OS_WIN)
207 void WebCursor::Clear() {
208 type_
= WebCursorInfo::TypePointer
;
211 custom_size_
.set_width(0);
212 custom_size_
.set_height(0);
214 custom_data_
.clear();
215 CleanupPlatformData();
218 void WebCursor::Copy(const WebCursor
& other
) {
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
);
227 void WebCursor::SetCustomData(const SkBitmap
& bitmap
) {
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());
240 void WebCursor::ImageFromCustomData(SkBitmap
* image
) const {
241 if (custom_data_
.empty())
244 image
->setConfig(SkBitmap::kARGB_8888_Config
,
245 custom_size_
.width(),
246 custom_size_
.height());
247 if (!image
->allocPixels())
249 memcpy(image
->getPixels(), &custom_data_
[0], custom_data_
.size());
252 void WebCursor::ClampHotspot() {
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())));