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->tryAllocN32Pixels(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 263