|  | // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "content/common/cursors/webcursor.h" | 
|  |  | 
|  | #include "base/logging.h" | 
|  | #include "base/pickle.h" | 
|  | #include "build/build_config.h" | 
|  | #include "third_party/WebKit/public/platform/WebImage.h" | 
|  |  | 
|  | using blink::WebCursorInfo; | 
|  |  | 
|  | static const int kMaxCursorDimension = 1024; | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | WebCursor::WebCursor() | 
|  | : type_(WebCursorInfo::TypePointer), | 
|  | custom_scale_(1) { | 
|  | InitPlatformData(); | 
|  | } | 
|  |  | 
|  | WebCursor::~WebCursor() { | 
|  | Clear(); | 
|  | } | 
|  |  | 
|  | WebCursor::WebCursor(const WebCursor& other) { | 
|  | InitPlatformData(); | 
|  | Copy(other); | 
|  | } | 
|  |  | 
|  | const WebCursor& WebCursor::operator=(const WebCursor& other) { | 
|  | if (this == &other) | 
|  | return *this; | 
|  |  | 
|  | Clear(); | 
|  | Copy(other); | 
|  | return *this; | 
|  | } | 
|  |  | 
|  | void WebCursor::InitFromCursorInfo(const CursorInfo& cursor_info) { | 
|  | Clear(); | 
|  |  | 
|  | type_ = cursor_info.type; | 
|  | hotspot_ = cursor_info.hotspot; | 
|  | if (IsCustom()) | 
|  | SetCustomData(cursor_info.custom_image); | 
|  | custom_scale_ = cursor_info.image_scale_factor; | 
|  | CHECK(custom_scale_ > 0); | 
|  | ClampHotspot(); | 
|  | } | 
|  |  | 
|  | void WebCursor::GetCursorInfo(CursorInfo* cursor_info) const { | 
|  | cursor_info->type = static_cast<WebCursorInfo::Type>(type_); | 
|  | cursor_info->hotspot = hotspot_; | 
|  | ImageFromCustomData(&cursor_info->custom_image); | 
|  | cursor_info->image_scale_factor = custom_scale_; | 
|  | } | 
|  |  | 
|  | bool WebCursor::Deserialize(base::PickleIterator* iter) { | 
|  | int type, hotspot_x, hotspot_y, size_x, size_y, data_len; | 
|  | float scale; | 
|  | const char* data; | 
|  |  | 
|  | // Leave |this| unmodified unless we are going to return success. | 
|  | if (!iter->ReadInt(&type) || | 
|  | !iter->ReadInt(&hotspot_x) || | 
|  | !iter->ReadInt(&hotspot_y) || | 
|  | !iter->ReadLength(&size_x) || | 
|  | !iter->ReadLength(&size_y) || | 
|  | !iter->ReadFloat(&scale) || | 
|  | !iter->ReadData(&data, &data_len)) | 
|  | return false; | 
|  |  | 
|  | // Ensure the size is sane, and there is enough data. | 
|  | if (size_x > kMaxCursorDimension || | 
|  | size_y > kMaxCursorDimension) | 
|  | return false; | 
|  |  | 
|  | // Ensure scale isn't ridiculous, and the scaled image size is still sane. | 
|  | if (scale < 0.01 || scale > 100 || | 
|  | size_x / scale > kMaxCursorDimension || | 
|  | size_y / scale > kMaxCursorDimension) | 
|  | return false; | 
|  |  | 
|  | type_ = type; | 
|  |  | 
|  | if (type == WebCursorInfo::TypeCustom) { | 
|  | if (size_x > 0 && size_y > 0) { | 
|  | // The * 4 is because the expected format is an array of RGBA pixel | 
|  | // values. | 
|  | if (size_x * size_y * 4 != data_len) { | 
|  | LOG(WARNING) << "WebCursor's data length and image size mismatch: " | 
|  | << size_x << "x" << size_y << "x4 != " | 
|  | << data_len; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | hotspot_.set_x(hotspot_x); | 
|  | hotspot_.set_y(hotspot_y); | 
|  | custom_size_.set_width(size_x); | 
|  | custom_size_.set_height(size_y); | 
|  | custom_scale_ = scale; | 
|  | ClampHotspot(); | 
|  |  | 
|  | custom_data_.clear(); | 
|  | if (data_len > 0) { | 
|  | custom_data_.resize(data_len); | 
|  | memcpy(&custom_data_[0], data, data_len); | 
|  | } | 
|  | } | 
|  | } | 
|  | return DeserializePlatformData(iter); | 
|  | } | 
|  |  | 
|  | bool WebCursor::Serialize(base::Pickle* pickle) const { | 
|  | if (!pickle->WriteInt(type_) || | 
|  | !pickle->WriteInt(hotspot_.x()) || | 
|  | !pickle->WriteInt(hotspot_.y()) || | 
|  | !pickle->WriteInt(custom_size_.width()) || | 
|  | !pickle->WriteInt(custom_size_.height()) || | 
|  | !pickle->WriteFloat(custom_scale_)) | 
|  | return false; | 
|  |  | 
|  | const char* data = NULL; | 
|  | if (!custom_data_.empty()) | 
|  | data = &custom_data_[0]; | 
|  | if (!pickle->WriteData(data, custom_data_.size())) | 
|  | return false; | 
|  |  | 
|  | return SerializePlatformData(pickle); | 
|  | } | 
|  |  | 
|  | bool WebCursor::IsCustom() const { | 
|  | return type_ == WebCursorInfo::TypeCustom; | 
|  | } | 
|  |  | 
|  | bool WebCursor::IsEqual(const WebCursor& other) const { | 
|  | if (type_ != other.type_) | 
|  | return false; | 
|  |  | 
|  | if (!IsPlatformDataEqual(other)) | 
|  | return false; | 
|  |  | 
|  | return hotspot_ == other.hotspot_ && | 
|  | custom_size_ == other.custom_size_ && | 
|  | custom_scale_ == other.custom_scale_ && | 
|  | custom_data_ == other.custom_data_; | 
|  | } | 
|  |  | 
|  | void WebCursor::Clear() { | 
|  | type_ = WebCursorInfo::TypePointer; | 
|  | hotspot_.set_x(0); | 
|  | hotspot_.set_y(0); | 
|  | custom_size_.set_width(0); | 
|  | custom_size_.set_height(0); | 
|  | custom_scale_ = 1; | 
|  | custom_data_.clear(); | 
|  | CleanupPlatformData(); | 
|  | } | 
|  |  | 
|  | void WebCursor::Copy(const WebCursor& other) { | 
|  | type_ = other.type_; | 
|  | hotspot_ = other.hotspot_; | 
|  | custom_size_ = other.custom_size_; | 
|  | custom_scale_ = other.custom_scale_; | 
|  | custom_data_ = other.custom_data_; | 
|  | CopyPlatformData(other); | 
|  | } | 
|  |  | 
|  | void WebCursor::SetCustomData(const SkBitmap& bitmap) { | 
|  | CreateCustomData(bitmap, &custom_data_, &custom_size_); | 
|  | } | 
|  |  | 
|  | void WebCursor::CreateCustomData(const SkBitmap& bitmap, | 
|  | std::vector<char>* custom_data, | 
|  | gfx::Size* custom_size) { | 
|  | if (bitmap.empty()) | 
|  | return; | 
|  |  | 
|  | // Fill custom_data directly with the NativeImage pixels. | 
|  | custom_data->resize(bitmap.getSize()); | 
|  | if (!custom_data->empty()) { | 
|  | //This will divide color values by alpha (un-premultiply) if necessary | 
|  | SkImageInfo dstInfo = bitmap.info().makeAlphaType(kUnpremul_SkAlphaType); | 
|  | bitmap.readPixels(dstInfo, &(*custom_data)[0], dstInfo.minRowBytes(), 0, 0); | 
|  | } | 
|  | custom_size->set_width(bitmap.width()); | 
|  | custom_size->set_height(bitmap.height()); | 
|  | } | 
|  |  | 
|  | void WebCursor::ImageFromCustomData(SkBitmap* image) const { | 
|  | if (custom_data_.empty()) | 
|  | return; | 
|  |  | 
|  | SkImageInfo image_info = SkImageInfo::MakeN32(custom_size_.width(), | 
|  | custom_size_.height(), | 
|  | kUnpremul_SkAlphaType); | 
|  | if (!image->tryAllocPixels(image_info)) | 
|  | return; | 
|  | memcpy(image->getPixels(), &custom_data_[0], custom_data_.size()); | 
|  | } | 
|  |  | 
|  | void WebCursor::ClampHotspot() { | 
|  | if (!IsCustom()) | 
|  | return; | 
|  |  | 
|  | // Clamp the hotspot to the custom image's dimensions. | 
|  | hotspot_.set_x(std::max(0, | 
|  | std::min(custom_size_.width() - 1, hotspot_.x()))); | 
|  | hotspot_.set_y(std::max(0, | 
|  | std::min(custom_size_.height() - 1, hotspot_.y()))); | 
|  | } | 
|  |  | 
|  | }  // namespace content |