Home | History | Annotate | Download | only in cursors
      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