[SyncFS] Build indexes from FileTracker entries on disk.
[chromium-blink-merge.git] / content / common / cursors / webcursor_mac.mm
blob7ba1b29f965b9153027be7aaa40200a32048cd07
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.
5 #include "content/common/cursors/webcursor.h"
7 #import <AppKit/AppKit.h>
9 #include "base/logging.h"
10 #include "base/mac/mac_util.h"
11 #include "base/mac/scoped_cftyperef.h"
12 #include "base/mac/sdk_forward_declarations.h"
13 #include "content/public/common/content_client.h"
14 #include "grit/webkit_resources.h"
15 #include "skia/ext/skia_utils_mac.h"
16 #include "third_party/WebKit/public/platform/WebCursorInfo.h"
17 #include "third_party/WebKit/public/platform/WebSize.h"
18 #include "ui/gfx/image/image.h"
19 #include "ui/gfx/point_conversions.h"
20 #include "ui/gfx/size_conversions.h"
23 using blink::WebCursorInfo;
24 using blink::WebSize;
26 // Private interface to CoreCursor, as of Mac OS X 10.7. This is essentially the
27 // implementation of WKCursor in WebKitSystemInterface.
29 enum {
30   kArrowCursor = 0,
31   kIBeamCursor = 1,
32   kMakeAliasCursor = 2,
33   kOperationNotAllowedCursor = 3,
34   kBusyButClickableCursor = 4,
35   kCopyCursor = 5,
36   kClosedHandCursor = 11,
37   kOpenHandCursor = 12,
38   kPointingHandCursor = 13,
39   kCountingUpHandCursor = 14,
40   kCountingDownHandCursor = 15,
41   kCountingUpAndDownHandCursor = 16,
42   kResizeLeftCursor = 17,
43   kResizeRightCursor = 18,
44   kResizeLeftRightCursor = 19,
45   kCrosshairCursor = 20,
46   kResizeUpCursor = 21,
47   kResizeDownCursor = 22,
48   kResizeUpDownCursor = 23,
49   kContextualMenuCursor = 24,
50   kDisappearingItemCursor = 25,
51   kVerticalIBeamCursor = 26,
52   kResizeEastCursor = 27,
53   kResizeEastWestCursor = 28,
54   kResizeNortheastCursor = 29,
55   kResizeNortheastSouthwestCursor = 30,
56   kResizeNorthCursor = 31,
57   kResizeNorthSouthCursor = 32,
58   kResizeNorthwestCursor = 33,
59   kResizeNorthwestSoutheastCursor = 34,
60   kResizeSoutheastCursor = 35,
61   kResizeSouthCursor = 36,
62   kResizeSouthwestCursor = 37,
63   kResizeWestCursor = 38,
64   kMoveCursor = 39,
65   kHelpCursor = 40,  // Present on >= 10.7.3.
66   kCellCursor = 41,  // Present on >= 10.7.3.
67   kZoomInCursor = 42,  // Present on >= 10.7.3.
68   kZoomOutCursor = 43  // Present on >= 10.7.3.
70 typedef long long CrCoreCursorType;
72 @interface CrCoreCursor : NSCursor {
73  @private
74   CrCoreCursorType type_;
77 + (id)cursorWithType:(CrCoreCursorType)type;
78 - (id)initWithType:(CrCoreCursorType)type;
79 - (CrCoreCursorType)_coreCursorType;
81 @end
83 @implementation CrCoreCursor
85 + (id)cursorWithType:(CrCoreCursorType)type {
86   NSCursor* cursor = [[CrCoreCursor alloc] initWithType:type];
87   if ([cursor image])
88     return [cursor autorelease];
90   [cursor release];
91   return nil;
94 - (id)initWithType:(CrCoreCursorType)type {
95   if ((self = [super init])) {
96     type_ = type;
97   }
98   return self;
101 - (CrCoreCursorType)_coreCursorType {
102   return type_;
105 @end
107 namespace {
109 NSCursor* LoadCursor(int resource_id, int hotspot_x, int hotspot_y) {
110   const gfx::Image& cursor_image =
111       content::GetContentClient()->GetNativeImageNamed(resource_id);
112   DCHECK(!cursor_image.IsEmpty());
113   return [[[NSCursor alloc] initWithImage:cursor_image.ToNSImage()
114                                   hotSpot:NSMakePoint(hotspot_x,
115                                                       hotspot_y)] autorelease];
118 // Gets a specified cursor from CoreCursor, falling back to loading it from the
119 // image cache if CoreCursor cannot provide it.
120 NSCursor* GetCoreCursorWithFallback(CrCoreCursorType type,
121                                     int resource_id,
122                                     int hotspot_x,
123                                     int hotspot_y) {
124   if (base::mac::IsOSLionOrLater()) {
125     NSCursor* cursor = [CrCoreCursor cursorWithType:type];
126     if (cursor)
127       return cursor;
128   }
130   return LoadCursor(resource_id, hotspot_x, hotspot_y);
133 NSCursor* CreateCustomCursor(const std::vector<char>& custom_data,
134                              const gfx::Size& custom_size,
135                              float custom_scale,
136                              const gfx::Point& hotspot) {
137   // If the data is missing, leave the backing transparent.
138   void* data = NULL;
139   size_t data_size = 0;
140   if (!custom_data.empty()) {
141     // This is safe since we're not going to draw into the context we're
142     // creating.
143     data = const_cast<char*>(&custom_data[0]);
144     data_size = custom_data.size();
145   }
147   // If the size is empty, use a 1x1 transparent image.
148   gfx::Size size = custom_size;
149   if (size.IsEmpty()) {
150     size.SetSize(1, 1);
151     data = NULL;
152   }
154   SkBitmap bitmap;
155   if (bitmap.allocN32Pixels(size.width(), size.height()) && data)
156     memcpy(bitmap.getAddr32(0, 0), data, data_size);
157   else
158     bitmap.eraseARGB(0, 0, 0, 0);
160   // Convert from pixels to view units.
161   if (custom_scale == 0)
162     custom_scale = 1;
163   NSSize dip_size = NSSizeFromCGSize(gfx::ToFlooredSize(
164       gfx::ScaleSize(custom_size, 1 / custom_scale)).ToCGSize());
165   NSPoint dip_hotspot = NSPointFromCGPoint(gfx::ToFlooredPoint(
166       gfx::ScalePoint(hotspot, 1 / custom_scale)).ToCGPoint());
168   // Both the image and its representation need to have the same size for
169   // cursors to appear in high resolution on retina displays. Note that the
170   // size of a representation is not the same as pixelsWide or pixelsHigh.
171   NSImage* cursor_image = gfx::SkBitmapToNSImage(bitmap);
172   [cursor_image setSize:dip_size];
173   [[[cursor_image representations] objectAtIndex:0] setSize:dip_size];
175   NSCursor* cursor = [[NSCursor alloc] initWithImage:cursor_image
176                                              hotSpot:dip_hotspot];
178   return [cursor autorelease];
181 }  // namespace
183 namespace content {
185 // Match Safari's cursor choices; see platform/mac/CursorMac.mm .
186 gfx::NativeCursor WebCursor::GetNativeCursor() {
187   switch (type_) {
188     case WebCursorInfo::TypePointer:
189       return [NSCursor arrowCursor];
190     case WebCursorInfo::TypeCross:
191       return [NSCursor crosshairCursor];
192     case WebCursorInfo::TypeHand:
193       // If >= 10.7, the pointingHandCursor has a shadow so use it. Otherwise
194       // use the custom one.
195       if (base::mac::IsOSLionOrLater())
196         return [NSCursor pointingHandCursor];
197       else
198         return LoadCursor(IDR_LINK_CURSOR, 6, 1);
199     case WebCursorInfo::TypeIBeam:
200       return [NSCursor IBeamCursor];
201     case WebCursorInfo::TypeWait:
202       return GetCoreCursorWithFallback(kBusyButClickableCursor,
203                                        IDR_WAIT_CURSOR, 7, 7);
204     case WebCursorInfo::TypeHelp:
205       return GetCoreCursorWithFallback(kHelpCursor,
206                                        IDR_HELP_CURSOR, 8, 8);
207     case WebCursorInfo::TypeEastResize:
208     case WebCursorInfo::TypeEastPanning:
209       return GetCoreCursorWithFallback(kResizeEastCursor,
210                                        IDR_EAST_RESIZE_CURSOR, 14, 7);
211     case WebCursorInfo::TypeNorthResize:
212     case WebCursorInfo::TypeNorthPanning:
213       return GetCoreCursorWithFallback(kResizeNorthCursor,
214                                        IDR_NORTH_RESIZE_CURSOR, 7, 1);
215     case WebCursorInfo::TypeNorthEastResize:
216     case WebCursorInfo::TypeNorthEastPanning:
217       return GetCoreCursorWithFallback(kResizeNortheastCursor,
218                                        IDR_NORTHEAST_RESIZE_CURSOR, 14, 1);
219     case WebCursorInfo::TypeNorthWestResize:
220     case WebCursorInfo::TypeNorthWestPanning:
221       return GetCoreCursorWithFallback(kResizeNorthwestCursor,
222                                        IDR_NORTHWEST_RESIZE_CURSOR, 0, 0);
223     case WebCursorInfo::TypeSouthResize:
224     case WebCursorInfo::TypeSouthPanning:
225       return GetCoreCursorWithFallback(kResizeSouthCursor,
226                                        IDR_SOUTH_RESIZE_CURSOR, 7, 14);
227     case WebCursorInfo::TypeSouthEastResize:
228     case WebCursorInfo::TypeSouthEastPanning:
229       return GetCoreCursorWithFallback(kResizeSoutheastCursor,
230                                        IDR_SOUTHEAST_RESIZE_CURSOR, 14, 14);
231     case WebCursorInfo::TypeSouthWestResize:
232     case WebCursorInfo::TypeSouthWestPanning:
233       return GetCoreCursorWithFallback(kResizeSouthwestCursor,
234                                        IDR_SOUTHWEST_RESIZE_CURSOR, 1, 14);
235     case WebCursorInfo::TypeWestResize:
236     case WebCursorInfo::TypeWestPanning:
237       return GetCoreCursorWithFallback(kResizeWestCursor,
238                                        IDR_WEST_RESIZE_CURSOR, 1, 7);
239     case WebCursorInfo::TypeNorthSouthResize:
240       return GetCoreCursorWithFallback(kResizeNorthSouthCursor,
241                                        IDR_NORTHSOUTH_RESIZE_CURSOR, 7, 7);
242     case WebCursorInfo::TypeEastWestResize:
243       return GetCoreCursorWithFallback(kResizeEastWestCursor,
244                                        IDR_EASTWEST_RESIZE_CURSOR, 7, 7);
245     case WebCursorInfo::TypeNorthEastSouthWestResize:
246       return GetCoreCursorWithFallback(kResizeNortheastSouthwestCursor,
247                                        IDR_NORTHEASTSOUTHWEST_RESIZE_CURSOR,
248                                        7, 7);
249     case WebCursorInfo::TypeNorthWestSouthEastResize:
250       return GetCoreCursorWithFallback(kResizeNorthwestSoutheastCursor,
251                                        IDR_NORTHWESTSOUTHEAST_RESIZE_CURSOR,
252                                        7, 7);
253     case WebCursorInfo::TypeColumnResize:
254       return [NSCursor resizeLeftRightCursor];
255     case WebCursorInfo::TypeRowResize:
256       return [NSCursor resizeUpDownCursor];
257     case WebCursorInfo::TypeMiddlePanning:
258     case WebCursorInfo::TypeMove:
259       return GetCoreCursorWithFallback(kMoveCursor,
260                                        IDR_MOVE_CURSOR, 7, 7);
261     case WebCursorInfo::TypeVerticalText:
262       // IBeamCursorForVerticalLayout is >= 10.7.
263       if ([NSCursor respondsToSelector:@selector(IBeamCursorForVerticalLayout)])
264         return [NSCursor IBeamCursorForVerticalLayout];
265       else
266         return LoadCursor(IDR_VERTICALTEXT_CURSOR, 7, 7);
267     case WebCursorInfo::TypeCell:
268       return GetCoreCursorWithFallback(kCellCursor,
269                                        IDR_CELL_CURSOR, 7, 7);
270     case WebCursorInfo::TypeContextMenu:
271       return [NSCursor contextualMenuCursor];
272     case WebCursorInfo::TypeAlias:
273       return GetCoreCursorWithFallback(kMakeAliasCursor,
274                                        IDR_ALIAS_CURSOR, 11, 3);
275     case WebCursorInfo::TypeProgress:
276       return GetCoreCursorWithFallback(kBusyButClickableCursor,
277                                        IDR_PROGRESS_CURSOR, 3, 2);
278     case WebCursorInfo::TypeNoDrop:
279     case WebCursorInfo::TypeNotAllowed:
280       return [NSCursor operationNotAllowedCursor];
281     case WebCursorInfo::TypeCopy:
282       return [NSCursor dragCopyCursor];
283     case WebCursorInfo::TypeNone:
284       return LoadCursor(IDR_NONE_CURSOR, 7, 7);
285     case WebCursorInfo::TypeZoomIn:
286       return GetCoreCursorWithFallback(kZoomInCursor,
287                                        IDR_ZOOMIN_CURSOR, 7, 7);
288     case WebCursorInfo::TypeZoomOut:
289       return GetCoreCursorWithFallback(kZoomOutCursor,
290                                        IDR_ZOOMOUT_CURSOR, 7, 7);
291     case WebCursorInfo::TypeGrab:
292       return [NSCursor openHandCursor];
293     case WebCursorInfo::TypeGrabbing:
294       return [NSCursor closedHandCursor];
295     case WebCursorInfo::TypeCustom:
296       return CreateCustomCursor(
297           custom_data_, custom_size_, custom_scale_, hotspot_);
298   }
299   NOTREACHED();
300   return nil;
303 void WebCursor::InitFromNSCursor(NSCursor* cursor) {
304   CursorInfo cursor_info;
306   if ([cursor isEqual:[NSCursor arrowCursor]]) {
307     cursor_info.type = WebCursorInfo::TypePointer;
308   } else if ([cursor isEqual:[NSCursor IBeamCursor]]) {
309     cursor_info.type = WebCursorInfo::TypeIBeam;
310   } else if ([cursor isEqual:[NSCursor crosshairCursor]]) {
311     cursor_info.type = WebCursorInfo::TypeCross;
312   } else if ([cursor isEqual:[NSCursor pointingHandCursor]]) {
313     cursor_info.type = WebCursorInfo::TypeHand;
314   } else if ([cursor isEqual:[NSCursor resizeLeftCursor]]) {
315     cursor_info.type = WebCursorInfo::TypeWestResize;
316   } else if ([cursor isEqual:[NSCursor resizeRightCursor]]) {
317     cursor_info.type = WebCursorInfo::TypeEastResize;
318   } else if ([cursor isEqual:[NSCursor resizeLeftRightCursor]]) {
319     cursor_info.type = WebCursorInfo::TypeEastWestResize;
320   } else if ([cursor isEqual:[NSCursor resizeUpCursor]]) {
321     cursor_info.type = WebCursorInfo::TypeNorthResize;
322   } else if ([cursor isEqual:[NSCursor resizeDownCursor]]) {
323     cursor_info.type = WebCursorInfo::TypeSouthResize;
324   } else if ([cursor isEqual:[NSCursor resizeUpDownCursor]]) {
325     cursor_info.type = WebCursorInfo::TypeNorthSouthResize;
326   } else if ([cursor isEqual:[NSCursor openHandCursor]]) {
327     cursor_info.type = WebCursorInfo::TypeGrab;
328   } else if ([cursor isEqual:[NSCursor closedHandCursor]]) {
329     cursor_info.type = WebCursorInfo::TypeGrabbing;
330   } else if ([cursor isEqual:[NSCursor operationNotAllowedCursor]]) {
331     cursor_info.type = WebCursorInfo::TypeNotAllowed;
332   } else if ([cursor isEqual:[NSCursor dragCopyCursor]]) {
333     cursor_info.type = WebCursorInfo::TypeCopy;
334   } else if ([cursor isEqual:[NSCursor contextualMenuCursor]]) {
335     cursor_info.type = WebCursorInfo::TypeContextMenu;
336   } else if (
337       [NSCursor respondsToSelector:@selector(IBeamCursorForVerticalLayout)] &&
338       [cursor isEqual:[NSCursor IBeamCursorForVerticalLayout]]) {
339     cursor_info.type = WebCursorInfo::TypeVerticalText;
340   } else {
341     // Also handles the [NSCursor disappearingItemCursor] case. Quick-and-dirty
342     // image conversion; TODO(avi): do better.
343     CGImageRef cg_image = nil;
344     NSImage* image = [cursor image];
345     for (id rep in [image representations]) {
346       if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
347         cg_image = [rep CGImage];
348         break;
349       }
350     }
352     if (cg_image) {
353       cursor_info.type = WebCursorInfo::TypeCustom;
354       NSPoint hot_spot = [cursor hotSpot];
355       cursor_info.hotspot = gfx::Point(hot_spot.x, hot_spot.y);
356       cursor_info.custom_image = gfx::CGImageToSkBitmap(cg_image);
357     } else {
358       cursor_info.type = WebCursorInfo::TypePointer;
359     }
360   }
362   InitFromCursorInfo(cursor_info);
365 void WebCursor::InitPlatformData() {
366   return;
369 bool WebCursor::SerializePlatformData(Pickle* pickle) const {
370   return true;
373 bool WebCursor::DeserializePlatformData(PickleIterator* iter) {
374   return true;
377 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const {
378   return true;
381 void WebCursor::CleanupPlatformData() {
382   return;
385 void WebCursor::CopyPlatformData(const WebCursor& other) {
386   return;
389 }  // namespace content