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