| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "webkit/glue/webcursor.h" | 5 #include "webkit/glue/webcursor.h" |
| 6 | 6 |
| 7 #import <AppKit/AppKit.h> | 7 #import <AppKit/AppKit.h> |
| 8 #include <Carbon/Carbon.h> | 8 #include <Carbon/Carbon.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/mac/mac_util.h" | 11 #include "base/mac/mac_util.h" |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 // resource bundle instead of going through the image cache. | 52 // resource bundle instead of going through the image cache. |
| 53 NSCursor* LoadCursor(const char* name, int x, int y) { | 53 NSCursor* LoadCursor(const char* name, int x, int y) { |
| 54 NSString* file_name = [NSString stringWithUTF8String:name]; | 54 NSString* file_name = [NSString stringWithUTF8String:name]; |
| 55 DCHECK(file_name); | 55 DCHECK(file_name); |
| 56 NSImage* cursor_image = gfx::GetCachedImageWithName(file_name); | 56 NSImage* cursor_image = gfx::GetCachedImageWithName(file_name); |
| 57 DCHECK(cursor_image); | 57 DCHECK(cursor_image); |
| 58 return [[[NSCursor alloc] initWithImage:cursor_image | 58 return [[[NSCursor alloc] initWithImage:cursor_image |
| 59 hotSpot:NSMakePoint(x, y)] autorelease]; | 59 hotSpot:NSMakePoint(x, y)] autorelease]; |
| 60 } | 60 } |
| 61 | 61 |
| 62 // TODO(avi): When Skia becomes default, fold this function into the remaining |
| 63 // caller, InitFromCursor(). |
| 62 CGImageRef CreateCGImageFromCustomData(const std::vector<char>& custom_data, | 64 CGImageRef CreateCGImageFromCustomData(const std::vector<char>& custom_data, |
| 63 const gfx::Size& custom_size) { | 65 const gfx::Size& custom_size) { |
| 64 // This is safe since we're not going to draw into the context we're creating. | |
| 65 // The settings here match SetCustomData() below; keep in sync. | |
| 66 // If the data is missing, leave the backing transparent. | 66 // If the data is missing, leave the backing transparent. |
| 67 void* data = NULL; | 67 void* data = NULL; |
| 68 if (!custom_data.empty()) | 68 if (!custom_data.empty()) { |
| 69 // This is safe since we're not going to draw into the context we're |
| 70 // creating. |
| 69 data = const_cast<char*>(&custom_data[0]); | 71 data = const_cast<char*>(&custom_data[0]); |
| 72 } |
| 70 | 73 |
| 71 // If the size is empty, use a 1x1 transparent image. | 74 // If the size is empty, use a 1x1 transparent image. |
| 72 gfx::Size size = custom_size; | 75 gfx::Size size = custom_size; |
| 73 if (size.IsEmpty()) { | 76 if (size.IsEmpty()) { |
| 74 size.SetSize(1, 1); | 77 size.SetSize(1, 1); |
| 75 data = NULL; | 78 data = NULL; |
| 76 } | 79 } |
| 77 | 80 |
| 78 base::mac::ScopedCFTypeRef<CGColorSpaceRef> cg_color( | 81 base::mac::ScopedCFTypeRef<CGColorSpaceRef> cg_color( |
| 79 CGColorSpaceCreateDeviceRGB()); | 82 CGColorSpaceCreateDeviceRGB()); |
| 83 // The settings here match SetCustomData() below; keep in sync. |
| 80 base::mac::ScopedCFTypeRef<CGContextRef> context( | 84 base::mac::ScopedCFTypeRef<CGContextRef> context( |
| 81 CGBitmapContextCreate(data, | 85 CGBitmapContextCreate(data, |
| 82 size.width(), | 86 size.width(), |
| 83 size.height(), | 87 size.height(), |
| 84 8, | 88 8, |
| 85 size.width()*4, | 89 size.width()*4, |
| 86 cg_color.get(), | 90 cg_color.get(), |
| 87 kCGImageAlphaPremultipliedLast | | 91 kCGImageAlphaPremultipliedLast | |
| 88 kCGBitmapByteOrder32Big)); | 92 kCGBitmapByteOrder32Big)); |
| 89 return CGBitmapContextCreateImage(context.get()); | 93 return CGBitmapContextCreateImage(context.get()); |
| 90 } | 94 } |
| 91 | 95 |
| 92 NSCursor* CreateCustomCursor(const std::vector<char>& custom_data, | 96 NSCursor* CreateCustomCursor(const std::vector<char>& custom_data, |
| 93 const gfx::Size& custom_size, | 97 const gfx::Size& custom_size, |
| 94 const gfx::Point& hotspot) { | 98 const gfx::Point& hotspot) { |
| 99 #if WEBKIT_USING_SKIA |
| 100 // If the data is missing, leave the backing transparent. |
| 101 void* data = NULL; |
| 102 size_t data_size = 0; |
| 103 if (!custom_data.empty()) { |
| 104 // This is safe since we're not going to draw into the context we're |
| 105 // creating. |
| 106 data = const_cast<char*>(&custom_data[0]); |
| 107 data_size = custom_data.size(); |
| 108 } |
| 109 |
| 110 // If the size is empty, use a 1x1 transparent image. |
| 111 gfx::Size size = custom_size; |
| 112 if (size.IsEmpty()) { |
| 113 size.SetSize(1, 1); |
| 114 data = NULL; |
| 115 } |
| 116 |
| 117 SkBitmap bitmap; |
| 118 bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height()); |
| 119 bitmap.allocPixels(); |
| 120 if (data) |
| 121 memcpy(bitmap.getAddr32(0, 0), data, data_size); |
| 122 else |
| 123 bitmap.eraseARGB(0, 0, 0, 0); |
| 124 NSImage* cursor_image = gfx::SkBitmapToNSImage(bitmap); |
| 125 #else |
| 95 base::mac::ScopedCFTypeRef<CGImageRef> cg_image( | 126 base::mac::ScopedCFTypeRef<CGImageRef> cg_image( |
| 96 CreateCGImageFromCustomData(custom_data, custom_size)); | 127 CreateCGImageFromCustomData(custom_data, custom_size)); |
| 97 | 128 |
| 98 scoped_nsobject<NSBitmapImageRep> ns_bitmap( | 129 scoped_nsobject<NSBitmapImageRep> ns_bitmap( |
| 99 [[NSBitmapImageRep alloc] initWithCGImage:cg_image.get()]); | 130 [[NSBitmapImageRep alloc] initWithCGImage:cg_image.get()]); |
| 100 NSImage* cursor_image = [[NSImage alloc] init]; | 131 scoped_nsobject<NSImage> cursor_image([[NSImage alloc] init]); |
| 101 DCHECK(cursor_image); | 132 DCHECK(cursor_image); |
| 102 [cursor_image addRepresentation:ns_bitmap]; | 133 [cursor_image addRepresentation:ns_bitmap]; |
| 134 #endif // WEBKIT_USING_SKIA |
| 103 | 135 |
| 104 NSCursor* cursor = [[NSCursor alloc] initWithImage:cursor_image | 136 NSCursor* cursor = [[NSCursor alloc] initWithImage:cursor_image |
| 105 hotSpot:NSMakePoint(hotspot.x(), | 137 hotSpot:NSMakePoint(hotspot.x(), |
| 106 hotspot.y())]; | 138 hotspot.y())]; |
| 107 [cursor_image release]; | |
| 108 | 139 |
| 109 return [cursor autorelease]; | 140 return [cursor autorelease]; |
| 110 } | 141 } |
| 111 | 142 |
| 112 } // namespace | 143 } // namespace |
| 113 | 144 |
| 114 // We're (mostly) matching Safari's cursor choices; see | 145 // We're (mostly) matching Safari's cursor choices; see |
| 115 // platform/mac/CursorMac.mm . Note that Safari uses some magic in wkCursor to | 146 // platform/mac/CursorMac.mm . Note that Safari uses some magic in wkCursor to |
| 116 // access private system cursors. A sample implementation using the same | 147 // access private system cursors. A sample implementation using the same |
| 117 // technique can be found attached to http://crbug.com/92892 . However, it's not | 148 // technique can be found attached to http://crbug.com/92892 . However, it's not |
| 118 // clear that accessing system cursors this way is enough of a gain to risk | 149 // clear that accessing system cursors this way is enough of a gain to risk |
| 119 // using SPIs. Until the benefits more clearly outweigh the risks, API is all | 150 // using SPIs. Until the benefits more clearly outweigh the risks, API is all |
| 120 // that will be used. | 151 // that will be used. |
| 121 NSCursor* WebCursor::GetCursor() const { | 152 gfx::NativeCursor WebCursor::GetNativeCursor() { |
| 122 switch (type_) { | 153 switch (type_) { |
| 123 case WebCursorInfo::TypePointer: | 154 case WebCursorInfo::TypePointer: |
| 124 return [NSCursor arrowCursor]; | 155 return [NSCursor arrowCursor]; |
| 125 case WebCursorInfo::TypeCross: | 156 case WebCursorInfo::TypeCross: |
| 126 return [NSCursor crosshairCursor]; | 157 return [NSCursor crosshairCursor]; |
| 127 case WebCursorInfo::TypeHand: | 158 case WebCursorInfo::TypeHand: |
| 128 // If >= 10.7, the pointingHandCursor has a shadow so use it. Otherwise | 159 // If >= 10.7, the pointingHandCursor has a shadow so use it. Otherwise |
| 129 // use the custom one. | 160 // use the custom one. |
| 130 if (base::mac::IsOSLionOrLater()) | 161 if (base::mac::IsOSLionOrLater()) |
| 131 return [NSCursor pointingHandCursor]; | 162 return [NSCursor pointingHandCursor]; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 216 return [NSCursor openHandCursor]; | 247 return [NSCursor openHandCursor]; |
| 217 case WebCursorInfo::TypeGrabbing: | 248 case WebCursorInfo::TypeGrabbing: |
| 218 return [NSCursor closedHandCursor]; | 249 return [NSCursor closedHandCursor]; |
| 219 case WebCursorInfo::TypeCustom: | 250 case WebCursorInfo::TypeCustom: |
| 220 return CreateCustomCursor(custom_data_, custom_size_, hotspot_); | 251 return CreateCustomCursor(custom_data_, custom_size_, hotspot_); |
| 221 } | 252 } |
| 222 NOTREACHED(); | 253 NOTREACHED(); |
| 223 return nil; | 254 return nil; |
| 224 } | 255 } |
| 225 | 256 |
| 226 gfx::NativeCursor WebCursor::GetNativeCursor() { | |
| 227 return GetCursor(); | |
| 228 } | |
| 229 | |
| 230 void WebCursor::InitFromThemeCursor(ThemeCursor cursor) { | 257 void WebCursor::InitFromThemeCursor(ThemeCursor cursor) { |
| 231 WebKit::WebCursorInfo cursor_info; | 258 WebKit::WebCursorInfo cursor_info; |
| 232 | 259 |
| 233 switch (cursor) { | 260 switch (cursor) { |
| 234 case kThemeArrowCursor: | 261 case kThemeArrowCursor: |
| 235 cursor_info.type = WebCursorInfo::TypePointer; | 262 cursor_info.type = WebCursorInfo::TypePointer; |
| 236 break; | 263 break; |
| 237 case kThemeCopyArrowCursor: | 264 case kThemeCopyArrowCursor: |
| 238 cursor_info.type = WebCursorInfo::TypeCopy; | 265 cursor_info.type = WebCursorInfo::TypeCopy; |
| 239 break; | 266 break; |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 } | 357 } |
| 331 } | 358 } |
| 332 | 359 |
| 333 base::mac::ScopedCFTypeRef<CGImageRef> cg_image( | 360 base::mac::ScopedCFTypeRef<CGImageRef> cg_image( |
| 334 CreateCGImageFromCustomData(raw_data, custom_size)); | 361 CreateCGImageFromCustomData(raw_data, custom_size)); |
| 335 | 362 |
| 336 WebKit::WebCursorInfo cursor_info; | 363 WebKit::WebCursorInfo cursor_info; |
| 337 cursor_info.type = WebCursorInfo::TypeCustom; | 364 cursor_info.type = WebCursorInfo::TypeCustom; |
| 338 cursor_info.hotSpot = WebKit::WebPoint(cursor->hotSpot.h, cursor->hotSpot.v); | 365 cursor_info.hotSpot = WebKit::WebPoint(cursor->hotSpot.h, cursor->hotSpot.v); |
| 339 #if WEBKIT_USING_SKIA | 366 #if WEBKIT_USING_SKIA |
| 367 // TODO(avi): build the cursor image in Skia directly rather than going via |
| 368 // this roundabout path. |
| 340 cursor_info.customImage = gfx::CGImageToSkBitmap(cg_image.get()); | 369 cursor_info.customImage = gfx::CGImageToSkBitmap(cg_image.get()); |
| 341 #else | 370 #else |
| 342 cursor_info.customImage = cg_image.get(); | 371 cursor_info.customImage = cg_image.get(); |
| 343 #endif | 372 #endif |
| 344 | 373 |
| 345 InitFromCursorInfo(cursor_info); | 374 InitFromCursorInfo(cursor_info); |
| 346 } | 375 } |
| 347 | 376 |
| 348 void WebCursor::InitFromNSCursor(NSCursor* cursor) { | 377 void WebCursor::InitFromNSCursor(NSCursor* cursor) { |
| 349 WebKit::WebCursorInfo cursor_info; | 378 WebKit::WebCursorInfo cursor_info; |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 } | 476 } |
| 448 | 477 |
| 449 void WebCursor::ImageFromCustomData(WebImage* image) const { | 478 void WebCursor::ImageFromCustomData(WebImage* image) const { |
| 450 if (custom_data_.empty()) | 479 if (custom_data_.empty()) |
| 451 return; | 480 return; |
| 452 | 481 |
| 453 base::mac::ScopedCFTypeRef<CGImageRef> cg_image( | 482 base::mac::ScopedCFTypeRef<CGImageRef> cg_image( |
| 454 CreateCGImageFromCustomData(custom_data_, custom_size_)); | 483 CreateCGImageFromCustomData(custom_data_, custom_size_)); |
| 455 *image = cg_image.get(); | 484 *image = cg_image.get(); |
| 456 } | 485 } |
| 457 #endif | 486 #endif // !WEBKIT_USING_SKIA |
| 458 | 487 |
| 459 void WebCursor::InitPlatformData() { | 488 void WebCursor::InitPlatformData() { |
| 460 return; | 489 return; |
| 461 } | 490 } |
| 462 | 491 |
| 463 bool WebCursor::SerializePlatformData(Pickle* pickle) const { | 492 bool WebCursor::SerializePlatformData(Pickle* pickle) const { |
| 464 return true; | 493 return true; |
| 465 } | 494 } |
| 466 | 495 |
| 467 bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { | 496 bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) { |
| 468 return true; | 497 return true; |
| 469 } | 498 } |
| 470 | 499 |
| 471 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { | 500 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const { |
| 472 return true; | 501 return true; |
| 473 } | 502 } |
| 474 | 503 |
| 475 void WebCursor::CleanupPlatformData() { | 504 void WebCursor::CleanupPlatformData() { |
| 476 return; | 505 return; |
| 477 } | 506 } |
| 478 | 507 |
| 479 void WebCursor::CopyPlatformData(const WebCursor& other) { | 508 void WebCursor::CopyPlatformData(const WebCursor& other) { |
| 480 return; | 509 return; |
| 481 } | 510 } |
| OLD | NEW |