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 "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