From c407dc5cd9bdc5668497f21b26b09d988ab439de Mon Sep 17 00:00:00 2001
From: Ben Murdoch <benm@google.com>
Date: Thu, 29 Jul 2010 17:14:53 +0100
Subject: Merge Chromium src@r53293

Change-Id: Ia79acf8670f385cee48c45b0a75371d8e950af34
---
 webkit/glue/webcursor_mac.mm | 384 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 384 insertions(+)
 create mode 100644 webkit/glue/webcursor_mac.mm

(limited to 'webkit/glue/webcursor_mac.mm')

diff --git a/webkit/glue/webcursor_mac.mm b/webkit/glue/webcursor_mac.mm
new file mode 100644
index 0000000..a6e7fc0
--- /dev/null
+++ b/webkit/glue/webcursor_mac.mm
@@ -0,0 +1,384 @@
+// Copyright (c) 2008 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 "webkit/glue/webcursor.h"
+
+#import <AppKit/AppKit.h>
+#include <Carbon/Carbon.h>
+
+#include "base/logging.h"
+#include "base/nsimage_cache_mac.h"
+#include "base/scoped_cftyperef.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebCursorInfo.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebImage.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
+
+using WebKit::WebCursorInfo;
+using WebKit::WebImage;
+using WebKit::WebSize;
+
+namespace {
+
+// TODO: This image fetch can (and probably should) be serviced by the resource
+// resource bundle instead of going through nsimage_cache.
+NSCursor* LoadCursor(const char* name, int x, int y) {
+  NSString* file_name = [NSString stringWithUTF8String:name];
+  DCHECK(file_name);
+  NSImage* cursor_image = nsimage_cache::ImageNamed(file_name);
+  DCHECK(cursor_image);
+  return [[[NSCursor alloc] initWithImage:cursor_image
+                                  hotSpot:NSMakePoint(x, y)] autorelease];
+}
+
+CGImageRef CreateCGImageFromCustomData(const std::vector<char>& custom_data,
+                                       const gfx::Size& custom_size) {
+  scoped_cftyperef<CGColorSpaceRef> cg_color(CGColorSpaceCreateDeviceRGB());
+  // This is safe since we're not going to draw into the context we're creating.
+  void* data = const_cast<char*>(&custom_data[0]);
+  // The settings here match SetCustomData() below; keep in sync.
+  scoped_cftyperef<CGContextRef> context(
+      CGBitmapContextCreate(data,
+                            custom_size.width(),
+                            custom_size.height(),
+                            8,
+                            custom_size.width()*4,
+                            cg_color.get(),
+                            kCGImageAlphaPremultipliedLast |
+                            kCGBitmapByteOrder32Big));
+  return CGBitmapContextCreateImage(context.get());
+}
+
+NSCursor* CreateCustomCursor(const std::vector<char>& custom_data,
+                             const gfx::Size& custom_size,
+                             const gfx::Point& hotspot) {
+  // CG throws a cocoa exception if we try to create an empty image, which
+  // results in an infinite loop.  This CHECK ensures that we crash instead.
+  CHECK(!custom_data.empty());
+
+  scoped_cftyperef<CGImageRef> cg_image(
+      CreateCGImageFromCustomData(custom_data, custom_size));
+
+  NSBitmapImageRep* ns_bitmap =
+      [[NSBitmapImageRep alloc] initWithCGImage:cg_image.get()];
+  NSImage* cursor_image = [[NSImage alloc] init];
+  DCHECK(cursor_image);
+  [cursor_image addRepresentation:ns_bitmap];
+  [ns_bitmap release];
+
+  NSCursor* cursor = [[NSCursor alloc] initWithImage:cursor_image
+                                             hotSpot:NSMakePoint(hotspot.x(),
+                                                                 hotspot.y())];
+  [cursor_image release];
+
+  return [cursor autorelease];
+}
+
+}  // namespace
+
+// We're matching Safari's cursor choices; see platform/mac/CursorMac.mm
+NSCursor* WebCursor::GetCursor() const {
+  switch (type_) {
+    case WebCursorInfo::TypePointer:
+      return [NSCursor arrowCursor];
+    case WebCursorInfo::TypeCross:
+      return LoadCursor("crossHairCursor", 11, 11);
+    case WebCursorInfo::TypeHand:
+      return LoadCursor("linkCursor", 6, 1);
+    case WebCursorInfo::TypeIBeam:
+      return [NSCursor IBeamCursor];
+    case WebCursorInfo::TypeWait:
+      return LoadCursor("waitCursor", 7, 7);
+    case WebCursorInfo::TypeHelp:
+      return LoadCursor("helpCursor", 8, 8);
+    case WebCursorInfo::TypeEastResize:
+    case WebCursorInfo::TypeEastPanning:
+      return LoadCursor("eastResizeCursor", 14, 7);
+    case WebCursorInfo::TypeNorthResize:
+    case WebCursorInfo::TypeNorthPanning:
+      return LoadCursor("northResizeCursor", 7, 1);
+    case WebCursorInfo::TypeNorthEastResize:
+    case WebCursorInfo::TypeNorthEastPanning:
+      return LoadCursor("northEastResizeCursor", 14, 1);
+    case WebCursorInfo::TypeNorthWestResize:
+    case WebCursorInfo::TypeNorthWestPanning:
+      return LoadCursor("northWestResizeCursor", 0, 0);
+    case WebCursorInfo::TypeSouthResize:
+    case WebCursorInfo::TypeSouthPanning:
+      return LoadCursor("southResizeCursor", 7, 14);
+    case WebCursorInfo::TypeSouthEastResize:
+    case WebCursorInfo::TypeSouthEastPanning:
+      return LoadCursor("southEastResizeCursor", 14, 14);
+    case WebCursorInfo::TypeSouthWestResize:
+    case WebCursorInfo::TypeSouthWestPanning:
+      return LoadCursor("southWestResizeCursor", 1, 14);
+    case WebCursorInfo::TypeWestResize:
+    case WebCursorInfo::TypeWestPanning:
+      return LoadCursor("westResizeCursor", 1, 7);
+    case WebCursorInfo::TypeNorthSouthResize:
+      return LoadCursor("northSouthResizeCursor", 7, 7);
+    case WebCursorInfo::TypeEastWestResize:
+      return LoadCursor("eastWestResizeCursor", 7, 7);
+    case WebCursorInfo::TypeNorthEastSouthWestResize:
+      return LoadCursor("northEastSouthWestResizeCursor", 7, 7);
+    case WebCursorInfo::TypeNorthWestSouthEastResize:
+      return LoadCursor("northWestSouthEastResizeCursor", 7, 7);
+    case WebCursorInfo::TypeColumnResize:
+      return [NSCursor resizeLeftRightCursor];
+    case WebCursorInfo::TypeRowResize:
+      return [NSCursor resizeUpDownCursor];
+    case WebCursorInfo::TypeMiddlePanning:
+    case WebCursorInfo::TypeMove:
+      return LoadCursor("moveCursor", 7, 7);
+    case WebCursorInfo::TypeVerticalText:
+      return LoadCursor("verticalTextCursor", 7, 7);
+    case WebCursorInfo::TypeCell:
+      return LoadCursor("cellCursor", 7, 7);
+    case WebCursorInfo::TypeContextMenu:
+      return LoadCursor("contextMenuCursor", 3, 2);
+    case WebCursorInfo::TypeAlias:
+      return LoadCursor("aliasCursor", 11, 3);
+    case WebCursorInfo::TypeProgress:
+      return LoadCursor("progressCursor", 3, 2);
+    case WebCursorInfo::TypeNoDrop:
+      return LoadCursor("noDropCursor", 3, 1);
+    case WebCursorInfo::TypeCopy:
+      return LoadCursor("copyCursor", 3, 2);
+    case WebCursorInfo::TypeNone:
+      return LoadCursor("noneCursor", 7, 7);
+    case WebCursorInfo::TypeNotAllowed:
+      return LoadCursor("notAllowedCursor", 11, 11);
+    case WebCursorInfo::TypeZoomIn:
+      return LoadCursor("zoomInCursor", 7, 7);
+    case WebCursorInfo::TypeZoomOut:
+      return LoadCursor("zoomOutCursor", 7, 7);
+    case WebCursorInfo::TypeCustom:
+      return CreateCustomCursor(custom_data_, custom_size_, hotspot_);
+  }
+  NOTREACHED();
+  return nil;
+}
+
+void WebCursor::InitFromThemeCursor(ThemeCursor cursor) {
+  WebKit::WebCursorInfo cursor_info;
+
+  switch (cursor) {
+    case kThemeArrowCursor:
+      cursor_info.type = WebCursorInfo::TypePointer;
+      break;
+    case kThemeCopyArrowCursor:
+      cursor_info.type = WebCursorInfo::TypeCopy;
+      break;
+    case kThemeAliasArrowCursor:
+      cursor_info.type = WebCursorInfo::TypeAlias;
+      break;
+    case kThemeContextualMenuArrowCursor:
+      cursor_info.type = WebCursorInfo::TypeContextMenu;
+      break;
+    case kThemeIBeamCursor:
+      cursor_info.type = WebCursorInfo::TypeIBeam;
+      break;
+    case kThemeCrossCursor:
+    case kThemePlusCursor:
+      cursor_info.type = WebCursorInfo::TypeCross;
+      break;
+    case kThemeWatchCursor:
+    case kThemeSpinningCursor:
+      cursor_info.type = WebCursorInfo::TypeWait;
+      break;
+    case kThemeClosedHandCursor:
+    case kThemeOpenHandCursor:
+    case kThemePointingHandCursor:
+    case kThemeCountingUpHandCursor:
+    case kThemeCountingDownHandCursor:
+    case kThemeCountingUpAndDownHandCursor:
+      cursor_info.type = WebCursorInfo::TypeHand;
+      break;
+    case kThemeResizeLeftCursor:
+      cursor_info.type = WebCursorInfo::TypeWestResize;
+      break;
+    case kThemeResizeRightCursor:
+      cursor_info.type = WebCursorInfo::TypeEastResize;
+      break;
+    case kThemeResizeLeftRightCursor:
+      cursor_info.type = WebCursorInfo::TypeEastWestResize;
+      break;
+    case kThemeNotAllowedCursor:
+      cursor_info.type = WebCursorInfo::TypeNotAllowed;
+      break;
+    case kThemeResizeUpCursor:
+      cursor_info.type = WebCursorInfo::TypeNorthResize;
+      break;
+    case kThemeResizeDownCursor:
+      cursor_info.type = WebCursorInfo::TypeSouthResize;
+      break;
+    case kThemeResizeUpDownCursor:
+      cursor_info.type = WebCursorInfo::TypeNorthSouthResize;
+      break;
+    case kThemePoofCursor:  // *shrug*
+    default:
+      cursor_info.type = WebCursorInfo::TypePointer;
+      break;
+  }
+
+  InitFromCursorInfo(cursor_info);
+}
+
+void WebCursor::InitFromCursor(const Cursor* cursor) {
+  // This conversion isn't perfect (in particular, the inversion effect of
+  // data==1, mask==0 won't work). Not planning on fixing it.
+
+  gfx::Size custom_size(16, 16);
+  std::vector<char> raw_data;
+  for (int row = 0; row < 16; ++row) {
+    unsigned short data = cursor->data[row];
+    unsigned short mask = cursor->mask[row];
+
+    // The Core Endian flipper callback for 'CURS' doesn't flip Bits16 as if it
+    // were a short (which it is), so we flip it here.
+    data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF);
+    mask = ((mask << 8) & 0xFF00) | ((mask >> 8) & 0x00FF);
+
+    for (int bit = 0; bit < 16; ++bit) {
+      if (data & 0x8000) {
+        raw_data.push_back(0x00);
+        raw_data.push_back(0x00);
+        raw_data.push_back(0x00);
+      } else {
+        raw_data.push_back(0xFF);
+        raw_data.push_back(0xFF);
+        raw_data.push_back(0xFF);
+      }
+      if (mask & 0x8000)
+        raw_data.push_back(0xFF);
+      else
+        raw_data.push_back(0x00);
+      data <<= 1;
+      mask <<= 1;
+    }
+  }
+
+  scoped_cftyperef<CGImageRef> cg_image(
+      CreateCGImageFromCustomData(raw_data, custom_size));
+
+  WebKit::WebCursorInfo cursor_info;
+  cursor_info.type = WebCursorInfo::TypeCustom;
+  cursor_info.hotSpot = WebKit::WebPoint(cursor->hotSpot.h, cursor->hotSpot.v);
+  cursor_info.customImage = cg_image.get();
+
+  InitFromCursorInfo(cursor_info);
+}
+
+void WebCursor::InitFromNSCursor(NSCursor* cursor) {
+  WebKit::WebCursorInfo cursor_info;
+
+  if ([cursor isEqual:[NSCursor arrowCursor]]) {
+    cursor_info.type = WebCursorInfo::TypePointer;
+  } else if ([cursor isEqual:[NSCursor IBeamCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeIBeam;
+  } else if ([cursor isEqual:[NSCursor crosshairCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeCross;
+  } else if ([cursor isEqual:[NSCursor pointingHandCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeHand;
+  } else if ([cursor isEqual:[NSCursor resizeLeftCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeWestResize;
+  } else if ([cursor isEqual:[NSCursor resizeRightCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeEastResize;
+  } else if ([cursor isEqual:[NSCursor resizeLeftRightCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeEastWestResize;
+  } else if ([cursor isEqual:[NSCursor resizeUpCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeNorthResize;
+  } else if ([cursor isEqual:[NSCursor resizeDownCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeSouthResize;
+  } else if ([cursor isEqual:[NSCursor resizeUpDownCursor]]) {
+    cursor_info.type = WebCursorInfo::TypeNorthSouthResize;
+  } else {
+    // Also handles the [NSCursor closedHandCursor], [NSCursor openHandCursor],
+    // and [NSCursor disappearingItemCursor] cases. Quick-and-dirty image
+    // conversion; TODO(avi): do better.
+    CGImageRef cg_image = nil;
+    NSImage* image = [cursor image];
+    for (id rep in [image representations]) {
+      if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
+        cg_image = [rep CGImage];
+        break;
+      }
+    }
+
+    if (cg_image) {
+      cursor_info.type = WebCursorInfo::TypeCustom;
+      NSPoint hot_spot = [cursor hotSpot];
+      cursor_info.hotSpot = WebKit::WebPoint(hot_spot.x, hot_spot.y);
+      cursor_info.customImage = cg_image;
+    } else {
+      cursor_info.type = WebCursorInfo::TypePointer;
+    }
+  }
+
+  InitFromCursorInfo(cursor_info);
+}
+
+void WebCursor::SetCustomData(const WebImage& image) {
+  if (image.isNull())
+    return;
+
+  scoped_cftyperef<CGColorSpaceRef> cg_color(
+      CGColorSpaceCreateDeviceRGB());
+
+  const WebSize& image_dimensions = image.size();
+  int image_width = image_dimensions.width;
+  int image_height = image_dimensions.height;
+
+  size_t size = image_height * image_width * 4;
+  custom_data_.resize(size);
+  custom_size_.set_width(image_width);
+  custom_size_.set_height(image_height);
+
+  // These settings match up with the code in CreateCustomCursor() above; keep
+  // them in sync.
+  // TODO(avi): test to ensure that the flags here are correct for RGBA
+  scoped_cftyperef<CGContextRef> context(
+      CGBitmapContextCreate(&custom_data_[0],
+                            image_width,
+                            image_height,
+                            8,
+                            image_width * 4,
+                            cg_color.get(),
+                            kCGImageAlphaPremultipliedLast |
+                            kCGBitmapByteOrder32Big));
+  CGRect rect = CGRectMake(0, 0, image_width, image_height);
+  CGContextDrawImage(context.get(), rect, image.getCGImageRef());
+}
+
+void WebCursor::ImageFromCustomData(WebImage* image) const {
+  if (custom_data_.empty())
+    return;
+
+  scoped_cftyperef<CGImageRef> cg_image(
+      CreateCGImageFromCustomData(custom_data_, custom_size_));
+  *image = cg_image.get();
+}
+
+void WebCursor::InitPlatformData() {
+  return;
+}
+
+bool WebCursor::SerializePlatformData(Pickle* pickle) const {
+  return true;
+}
+
+bool WebCursor::DeserializePlatformData(const Pickle* pickle, void** iter) {
+  return true;
+}
+
+bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const {
+  return true;
+}
+
+void WebCursor::CleanupPlatformData() {
+  return;
+}
+
+void WebCursor::CopyPlatformData(const WebCursor& other) {
+  return;
+}
-- 
cgit v1.1