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 "content/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;
17 WebCursor::WebCursor()
18 : type_(WebCursorInfo::TypePointer
),
21 external_cursor_
= NULL
;
26 WebCursor::WebCursor(const CursorInfo
& cursor_info
)
27 : type_(WebCursorInfo::TypePointer
) {
29 external_cursor_
= NULL
;
32 InitFromCursorInfo(cursor_info
);
35 WebCursor::~WebCursor() {
39 WebCursor::WebCursor(const WebCursor
& other
) {
44 const WebCursor
& WebCursor::operator=(const WebCursor
& other
) {
53 void WebCursor::InitFromCursorInfo(const CursorInfo
& cursor_info
) {
57 if (cursor_info
.external_handle
) {
58 InitFromExternalCursor(cursor_info
.external_handle
);
63 type_
= cursor_info
.type
;
64 hotspot_
= cursor_info
.hotspot
;
66 SetCustomData(cursor_info
.custom_image
);
67 custom_scale_
= cursor_info
.image_scale_factor
;
68 CHECK(custom_scale_
> 0);
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_
;
79 cursor_info
->external_handle
= external_cursor_
;
83 bool WebCursor::Deserialize(base::PickleIterator
* iter
) {
84 int type
, hotspot_x
, hotspot_y
, size_x
, size_y
, data_len
;
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
))
98 // Ensure the size is sane, and there is enough data.
99 if (size_x
> kMaxCursorDimension
||
100 size_y
> kMaxCursorDimension
)
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
)
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
115 if (size_x
* size_y
* 4 > data_len
)
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
;
125 custom_data_
.clear();
127 custom_data_
.resize(data_len
);
128 memcpy(&custom_data_
[0], data
, data_len
);
132 return DeserializePlatformData(iter
);
135 bool WebCursor::Serialize(base::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_
))
144 const char* data
= NULL
;
145 if (!custom_data_
.empty())
146 data
= &custom_data_
[0];
147 if (!pickle
->WriteData(data
, custom_data_
.size()))
150 return SerializePlatformData(pickle
);
153 bool WebCursor::IsCustom() const {
154 return type_
== WebCursorInfo::TypeCustom
;
157 bool WebCursor::IsEqual(const WebCursor
& other
) const {
158 if (type_
!= other
.type_
)
161 if (!IsPlatformDataEqual(other
))
164 return hotspot_
== other
.hotspot_
&&
165 custom_size_
== other
.custom_size_
&&
166 custom_scale_
== other
.custom_scale_
&&
167 custom_data_
== other
.custom_data_
;
172 static WebCursorInfo::Type
ToCursorType(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
},
191 for (int i
= 0; i
< arraysize(kStandardCursors
); ++i
) {
192 if (cursor
== kStandardCursors
[i
].cursor
)
193 return kStandardCursors
[i
].type
;
195 return WebCursorInfo::TypeCustom
;
198 void WebCursor::InitFromExternalCursor(HCURSOR cursor
) {
199 WebCursorInfo::Type cursor_type
= ToCursorType(cursor
);
201 InitFromCursorInfo(CursorInfo(cursor_type
));
203 if (cursor_type
== WebCursorInfo::TypeCustom
)
204 external_cursor_
= cursor
;
207 #endif // defined(OS_WIN)
209 void WebCursor::Clear() {
210 type_
= WebCursorInfo::TypePointer
;
213 custom_size_
.set_width(0);
214 custom_size_
.set_height(0);
216 custom_data_
.clear();
217 CleanupPlatformData();
220 void WebCursor::Copy(const WebCursor
& other
) {
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
);
229 void WebCursor::SetCustomData(const SkBitmap
& bitmap
) {
233 // Fill custom_data_ directly with the NativeImage pixels.
234 custom_data_
.resize(bitmap
.getSize());
235 if (!custom_data_
.empty()) {
236 //This will divide color values by alpha (un-premultiply) if necessary
237 SkImageInfo dstInfo
= bitmap
.info().makeAlphaType(kUnpremul_SkAlphaType
);
238 bitmap
.readPixels(dstInfo
, &custom_data_
[0], dstInfo
.minRowBytes(), 0, 0);
240 custom_size_
.set_width(bitmap
.width());
241 custom_size_
.set_height(bitmap
.height());
244 void WebCursor::ImageFromCustomData(SkBitmap
* image
) const {
245 if (custom_data_
.empty())
248 SkImageInfo image_info
= SkImageInfo::MakeN32(custom_size_
.width(),
249 custom_size_
.height(),
250 kUnpremul_SkAlphaType
);
251 if (!image
->tryAllocPixels(image_info
))
253 memcpy(image
->getPixels(), &custom_data_
[0], custom_data_
.size());
256 void WebCursor::ClampHotspot() {
260 // Clamp the hotspot to the custom image's dimensions.
261 hotspot_
.set_x(std::max(0,
262 std::min(custom_size_
.width() - 1, hotspot_
.x())));
263 hotspot_
.set_y(std::max(0,
264 std::min(custom_size_
.height() - 1, hotspot_
.y())));
267 } // namespace content