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 } 262