Display new Autofill UI Contents in Views
[chromium-blink-merge.git] / webkit / glue / webcursor_mac.mm
blobb067d9c878ed4c5bc1a2509e85e6e9ae81695e60
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 "webkit/glue/webcursor.h"
7 #import <AppKit/AppKit.h>
8 #include <Carbon/Carbon.h>
10 #include "base/logging.h"
11 #include "base/mac/mac_util.h"
12 #include "base/mac/scoped_cftyperef.h"
13 #include "base/memory/scoped_nsobject.h"
14 #include "grit/webkit_chromium_resources.h"
15 #include "skia/ext/skia_utils_mac.h"
16 #include "third_party/WebKit/Source/WebKit/chromium/public/WebCursorInfo.h"
17 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebImage.h"
18 #include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebSize.h"
19 #include "ui/base/resource/resource_bundle.h"
22 #if defined(MAC_OS_X_VERSION_10_7) && \
23     MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7
24 // The 10.7 SDK no longer has QuickDraw headers.
25 // http://developer.apple.com/legacy/mac/library/documentation/Carbon/reference/QuickDraw_Ref/QuickDraw_Ref.pdf
26 typedef short Bits16[16];
27 struct Cursor {
28   Bits16 data;
29   Bits16 mask;
30   Point hotSpot;
32 #endif  // 10.7+ SDK
34 using WebKit::WebCursorInfo;
35 using WebKit::WebImage;
36 using WebKit::WebSize;
38 // Declare symbols that are part of the 10.7 SDK.
39 #if !defined(MAC_OS_X_VERSION_10_7) || \
40     MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
42 @interface NSCursor (LionSDKDeclarations)
43 + (NSCursor*)IBeamCursorForVerticalLayout;
44 @end
46 #endif  // MAC_OS_X_VERSION_10_7
48 // Private interface to CoreCursor, as of Mac OS X 10.7. This is essentially the
49 // implementation of WKCursor in WebKitSystemInterface.
51 enum {
52   kArrowCursor = 0,
53   kIBeamCursor = 1,
54   kMakeAliasCursor = 2,
55   kOperationNotAllowedCursor = 3,
56   kBusyButClickableCursor = 4,
57   kCopyCursor = 5,
58   kClosedHandCursor = 11,
59   kOpenHandCursor = 12,
60   kPointingHandCursor = 13,
61   kCountingUpHandCursor = 14,
62   kCountingDownHandCursor = 15,
63   kCountingUpAndDownHandCursor = 16,
64   kResizeLeftCursor = 17,
65   kResizeRightCursor = 18,
66   kResizeLeftRightCursor = 19,
67   kCrosshairCursor = 20,
68   kResizeUpCursor = 21,
69   kResizeDownCursor = 22,
70   kResizeUpDownCursor = 23,
71   kContextualMenuCursor = 24,
72   kDisappearingItemCursor = 25,
73   kVerticalIBeamCursor = 26,
74   kResizeEastCursor = 27,
75   kResizeEastWestCursor = 28,
76   kResizeNortheastCursor = 29,
77   kResizeNortheastSouthwestCursor = 30,
78   kResizeNorthCursor = 31,
79   kResizeNorthSouthCursor = 32,
80   kResizeNorthwestCursor = 33,
81   kResizeNorthwestSoutheastCursor = 34,
82   kResizeSoutheastCursor = 35,
83   kResizeSouthCursor = 36,
84   kResizeSouthwestCursor = 37,
85   kResizeWestCursor = 38,
86   kMoveCursor = 39,
87   kHelpCursor = 40,  // Present on >= 10.7.3.
88   kCellCursor = 41,  // Present on >= 10.7.3.
89   kZoomInCursor = 42,  // Present on >= 10.7.3.
90   kZoomOutCursor = 43  // Present on >= 10.7.3.
92 typedef long long CrCoreCursorType;
94 @interface CrCoreCursor : NSCursor {
95  @private
96   CrCoreCursorType type_;
99 + (id)cursorWithType:(CrCoreCursorType)type;
100 - (id)initWithType:(CrCoreCursorType)type;
101 - (CrCoreCursorType)_coreCursorType;
103 @end
105 @implementation CrCoreCursor
107 + (id)cursorWithType:(CrCoreCursorType)type {
108   NSCursor* cursor = [[CrCoreCursor alloc] initWithType:type];
109   if ([cursor image])
110     return [cursor autorelease];
112   [cursor release];
113   return nil;
116 - (id)initWithType:(CrCoreCursorType)type {
117   if ((self = [super init])) {
118     type_ = type;
119   }
120   return self;
123 - (CrCoreCursorType)_coreCursorType {
124   return type_;
127 @end
129 namespace {
131 NSCursor* LoadCursor(int resource_id, int hotspot_x, int hotspot_y) {
132   const gfx::Image& cursor_image =
133       ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id);
134   DCHECK(!cursor_image.IsEmpty());
135   return [[[NSCursor alloc] initWithImage:cursor_image.ToNSImage()
136                                   hotSpot:NSMakePoint(hotspot_x,
137                                                       hotspot_y)] autorelease];
140 // Gets a specified cursor from CoreCursor, falling back to loading it from the
141 // image cache if CoreCursor cannot provide it.
142 NSCursor* GetCoreCursorWithFallback(CrCoreCursorType type,
143                                     int resource_id,
144                                     int hotspot_x,
145                                     int hotspot_y) {
146   if (base::mac::IsOSLionOrLater()) {
147     NSCursor* cursor = [CrCoreCursor cursorWithType:type];
148     if (cursor)
149       return cursor;
150   }
152   return LoadCursor(resource_id, hotspot_x, hotspot_y);
155 // TODO(avi): When Skia becomes default, fold this function into the remaining
156 // caller, InitFromCursor().
157 CGImageRef CreateCGImageFromCustomData(const std::vector<char>& custom_data,
158                                        const gfx::Size& custom_size) {
159   // If the data is missing, leave the backing transparent.
160   void* data = NULL;
161   if (!custom_data.empty()) {
162     // This is safe since we're not going to draw into the context we're
163     // creating.
164     data = const_cast<char*>(&custom_data[0]);
165   }
167   // If the size is empty, use a 1x1 transparent image.
168   gfx::Size size = custom_size;
169   if (size.IsEmpty()) {
170     size.SetSize(1, 1);
171     data = NULL;
172   }
174   base::mac::ScopedCFTypeRef<CGColorSpaceRef> cg_color(
175       CGColorSpaceCreateDeviceRGB());
176   // The settings here match SetCustomData() below; keep in sync.
177   base::mac::ScopedCFTypeRef<CGContextRef> context(
178       CGBitmapContextCreate(data,
179                             size.width(),
180                             size.height(),
181                             8,
182                             size.width()*4,
183                             cg_color.get(),
184                             kCGImageAlphaPremultipliedLast |
185                             kCGBitmapByteOrder32Big));
186   return CGBitmapContextCreateImage(context.get());
189 NSCursor* CreateCustomCursor(const std::vector<char>& custom_data,
190                              const gfx::Size& custom_size,
191                              const gfx::Point& hotspot) {
192   // If the data is missing, leave the backing transparent.
193   void* data = NULL;
194   size_t data_size = 0;
195   if (!custom_data.empty()) {
196     // This is safe since we're not going to draw into the context we're
197     // creating.
198     data = const_cast<char*>(&custom_data[0]);
199     data_size = custom_data.size();
200   }
202   // If the size is empty, use a 1x1 transparent image.
203   gfx::Size size = custom_size;
204   if (size.IsEmpty()) {
205     size.SetSize(1, 1);
206     data = NULL;
207   }
209   SkBitmap bitmap;
210   bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height());
211   bitmap.allocPixels();
212   if (data)
213     memcpy(bitmap.getAddr32(0, 0), data, data_size);
214   else
215     bitmap.eraseARGB(0, 0, 0, 0);
216   NSImage* cursor_image = gfx::SkBitmapToNSImage(bitmap);
218   NSCursor* cursor = [[NSCursor alloc] initWithImage:cursor_image
219                                              hotSpot:NSMakePoint(hotspot.x(),
220                                                                  hotspot.y())];
222   return [cursor autorelease];
225 }  // namespace
227 // Match Safari's cursor choices; see platform/mac/CursorMac.mm .
228 gfx::NativeCursor WebCursor::GetNativeCursor() {
229   switch (type_) {
230     case WebCursorInfo::TypePointer:
231       return [NSCursor arrowCursor];
232     case WebCursorInfo::TypeCross:
233       return [NSCursor crosshairCursor];
234     case WebCursorInfo::TypeHand:
235       // If >= 10.7, the pointingHandCursor has a shadow so use it. Otherwise
236       // use the custom one.
237       if (base::mac::IsOSLionOrLater())
238         return [NSCursor pointingHandCursor];
239       else
240         return LoadCursor(IDR_LINK_CURSOR, 6, 1);
241     case WebCursorInfo::TypeIBeam:
242       return [NSCursor IBeamCursor];
243     case WebCursorInfo::TypeWait:
244       return GetCoreCursorWithFallback(kBusyButClickableCursor,
245                                        IDR_WAIT_CURSOR, 7, 7);
246     case WebCursorInfo::TypeHelp:
247       return GetCoreCursorWithFallback(kHelpCursor,
248                                        IDR_HELP_CURSOR, 8, 8);
249     case WebCursorInfo::TypeEastResize:
250     case WebCursorInfo::TypeEastPanning:
251       return GetCoreCursorWithFallback(kResizeEastCursor,
252                                        IDR_EAST_RESIZE_CURSOR, 14, 7);
253     case WebCursorInfo::TypeNorthResize:
254     case WebCursorInfo::TypeNorthPanning:
255       return GetCoreCursorWithFallback(kResizeNorthCursor,
256                                        IDR_NORTH_RESIZE_CURSOR, 7, 1);
257     case WebCursorInfo::TypeNorthEastResize:
258     case WebCursorInfo::TypeNorthEastPanning:
259       return GetCoreCursorWithFallback(kResizeNortheastCursor,
260                                        IDR_NORTHEAST_RESIZE_CURSOR, 14, 1);
261     case WebCursorInfo::TypeNorthWestResize:
262     case WebCursorInfo::TypeNorthWestPanning:
263       return GetCoreCursorWithFallback(kResizeNorthwestCursor,
264                                        IDR_NORTHWEST_RESIZE_CURSOR, 0, 0);
265     case WebCursorInfo::TypeSouthResize:
266     case WebCursorInfo::TypeSouthPanning:
267       return GetCoreCursorWithFallback(kResizeSouthCursor,
268                                        IDR_SOUTH_RESIZE_CURSOR, 7, 14);
269     case WebCursorInfo::TypeSouthEastResize:
270     case WebCursorInfo::TypeSouthEastPanning:
271       return GetCoreCursorWithFallback(kResizeSoutheastCursor,
272                                        IDR_SOUTHEAST_RESIZE_CURSOR, 14, 14);
273     case WebCursorInfo::TypeSouthWestResize:
274     case WebCursorInfo::TypeSouthWestPanning:
275       return GetCoreCursorWithFallback(kResizeSouthwestCursor,
276                                        IDR_SOUTHWEST_RESIZE_CURSOR, 1, 14);
277     case WebCursorInfo::TypeWestResize:
278     case WebCursorInfo::TypeWestPanning:
279       return GetCoreCursorWithFallback(kResizeWestCursor,
280                                        IDR_WEST_RESIZE_CURSOR, 1, 7);
281     case WebCursorInfo::TypeNorthSouthResize:
282       return GetCoreCursorWithFallback(kResizeNorthSouthCursor,
283                                        IDR_NORTHSOUTH_RESIZE_CURSOR, 7, 7);
284     case WebCursorInfo::TypeEastWestResize:
285       return GetCoreCursorWithFallback(kResizeEastWestCursor,
286                                        IDR_EASTWEST_RESIZE_CURSOR, 7, 7);
287     case WebCursorInfo::TypeNorthEastSouthWestResize:
288       return GetCoreCursorWithFallback(kResizeNortheastSouthwestCursor,
289                                        IDR_NORTHEASTSOUTHWEST_RESIZE_CURSOR,
290                                        7, 7);
291     case WebCursorInfo::TypeNorthWestSouthEastResize:
292       return GetCoreCursorWithFallback(kResizeNorthwestSoutheastCursor,
293                                        IDR_NORTHWESTSOUTHEAST_RESIZE_CURSOR,
294                                        7, 7);
295     case WebCursorInfo::TypeColumnResize:
296       return [NSCursor resizeLeftRightCursor];
297     case WebCursorInfo::TypeRowResize:
298       return [NSCursor resizeUpDownCursor];
299     case WebCursorInfo::TypeMiddlePanning:
300     case WebCursorInfo::TypeMove:
301       return GetCoreCursorWithFallback(kMoveCursor,
302                                        IDR_MOVE_CURSOR, 7, 7);
303     case WebCursorInfo::TypeVerticalText:
304       // IBeamCursorForVerticalLayout is >= 10.7.
305       if ([NSCursor respondsToSelector:@selector(IBeamCursorForVerticalLayout)])
306         return [NSCursor IBeamCursorForVerticalLayout];
307       else
308         return LoadCursor(IDR_VERTICALTEXT_CURSOR, 7, 7);
309     case WebCursorInfo::TypeCell:
310       return GetCoreCursorWithFallback(kCellCursor,
311                                        IDR_CELL_CURSOR, 7, 7);
312     case WebCursorInfo::TypeContextMenu:
313       // contextualMenuCursor is >= 10.6.
314       if ([NSCursor respondsToSelector:@selector(contextualMenuCursor)])
315         return [NSCursor contextualMenuCursor];
316       else
317         return LoadCursor(IDR_CONTEXTMENU_CURSOR, 3, 2);
318     case WebCursorInfo::TypeAlias:
319       return GetCoreCursorWithFallback(kMakeAliasCursor,
320                                        IDR_ALIAS_CURSOR, 11, 3);
321     case WebCursorInfo::TypeProgress:
322       return GetCoreCursorWithFallback(kBusyButClickableCursor,
323                                        IDR_PROGRESS_CURSOR, 3, 2);
324     case WebCursorInfo::TypeNoDrop:
325     case WebCursorInfo::TypeNotAllowed:
326       // Docs say that operationNotAllowedCursor is >= 10.6, and it's not in the
327       // 10.5 SDK, but later SDKs note that it really is available on 10.5.
328       return [NSCursor operationNotAllowedCursor];
329     case WebCursorInfo::TypeCopy:
330       // dragCopyCursor is >= 10.6.
331       if ([NSCursor respondsToSelector:@selector(dragCopyCursor)])
332         return [NSCursor dragCopyCursor];
333       else
334         return LoadCursor(IDR_COPY_CURSOR, 3, 2);
335     case WebCursorInfo::TypeNone:
336       return LoadCursor(IDR_NONE_CURSOR, 7, 7);
337     case WebCursorInfo::TypeZoomIn:
338       return GetCoreCursorWithFallback(kZoomInCursor,
339                                        IDR_ZOOMIN_CURSOR, 7, 7);
340     case WebCursorInfo::TypeZoomOut:
341       return GetCoreCursorWithFallback(kZoomOutCursor,
342                                        IDR_ZOOMOUT_CURSOR, 7, 7);
343     case WebCursorInfo::TypeGrab:
344       return [NSCursor openHandCursor];
345     case WebCursorInfo::TypeGrabbing:
346       return [NSCursor closedHandCursor];
347     case WebCursorInfo::TypeCustom:
348       return CreateCustomCursor(custom_data_, custom_size_, hotspot_);
349   }
350   NOTREACHED();
351   return nil;
354 void WebCursor::InitFromThemeCursor(ThemeCursor cursor) {
355   WebKit::WebCursorInfo cursor_info;
357   switch (cursor) {
358     case kThemeArrowCursor:
359       cursor_info.type = WebCursorInfo::TypePointer;
360       break;
361     case kThemeCopyArrowCursor:
362       cursor_info.type = WebCursorInfo::TypeCopy;
363       break;
364     case kThemeAliasArrowCursor:
365       cursor_info.type = WebCursorInfo::TypeAlias;
366       break;
367     case kThemeContextualMenuArrowCursor:
368       cursor_info.type = WebCursorInfo::TypeContextMenu;
369       break;
370     case kThemeIBeamCursor:
371       cursor_info.type = WebCursorInfo::TypeIBeam;
372       break;
373     case kThemeCrossCursor:
374     case kThemePlusCursor:
375       cursor_info.type = WebCursorInfo::TypeCross;
376       break;
377     case kThemeWatchCursor:
378     case kThemeSpinningCursor:
379       cursor_info.type = WebCursorInfo::TypeWait;
380       break;
381     case kThemeClosedHandCursor:
382       cursor_info.type = WebCursorInfo::TypeGrabbing;
383       break;
384     case kThemeOpenHandCursor:
385       cursor_info.type = WebCursorInfo::TypeGrab;
386       break;
387     case kThemePointingHandCursor:
388     case kThemeCountingUpHandCursor:
389     case kThemeCountingDownHandCursor:
390     case kThemeCountingUpAndDownHandCursor:
391       cursor_info.type = WebCursorInfo::TypeHand;
392       break;
393     case kThemeResizeLeftCursor:
394       cursor_info.type = WebCursorInfo::TypeWestResize;
395       break;
396     case kThemeResizeRightCursor:
397       cursor_info.type = WebCursorInfo::TypeEastResize;
398       break;
399     case kThemeResizeLeftRightCursor:
400       cursor_info.type = WebCursorInfo::TypeEastWestResize;
401       break;
402     case kThemeNotAllowedCursor:
403       cursor_info.type = WebCursorInfo::TypeNotAllowed;
404       break;
405     case kThemeResizeUpCursor:
406       cursor_info.type = WebCursorInfo::TypeNorthResize;
407       break;
408     case kThemeResizeDownCursor:
409       cursor_info.type = WebCursorInfo::TypeSouthResize;
410       break;
411     case kThemeResizeUpDownCursor:
412       cursor_info.type = WebCursorInfo::TypeNorthSouthResize;
413       break;
414     case kThemePoofCursor:  // *shrug*
415     default:
416       cursor_info.type = WebCursorInfo::TypePointer;
417       break;
418   }
420   InitFromCursorInfo(cursor_info);
423 void WebCursor::InitFromCursor(const Cursor* cursor) {
424   // This conversion isn't perfect (in particular, the inversion effect of
425   // data==1, mask==0 won't work). Not planning on fixing it.
427   gfx::Size custom_size(16, 16);
428   std::vector<char> raw_data;
429   for (int row = 0; row < 16; ++row) {
430     unsigned short data = cursor->data[row];
431     unsigned short mask = cursor->mask[row];
433     // The Core Endian flipper callback for 'CURS' doesn't flip Bits16 as if it
434     // were a short (which it is), so we flip it here.
435     data = ((data << 8) & 0xFF00) | ((data >> 8) & 0x00FF);
436     mask = ((mask << 8) & 0xFF00) | ((mask >> 8) & 0x00FF);
438     for (int bit = 0; bit < 16; ++bit) {
439       if (data & 0x8000) {
440         raw_data.push_back(0x00);
441         raw_data.push_back(0x00);
442         raw_data.push_back(0x00);
443       } else {
444         raw_data.push_back(0xFF);
445         raw_data.push_back(0xFF);
446         raw_data.push_back(0xFF);
447       }
448       if (mask & 0x8000)
449         raw_data.push_back(0xFF);
450       else
451         raw_data.push_back(0x00);
452       data <<= 1;
453       mask <<= 1;
454     }
455   }
457   base::mac::ScopedCFTypeRef<CGImageRef> cg_image(
458       CreateCGImageFromCustomData(raw_data, custom_size));
460   WebKit::WebCursorInfo cursor_info;
461   cursor_info.type = WebCursorInfo::TypeCustom;
462   cursor_info.hotSpot = WebKit::WebPoint(cursor->hotSpot.h, cursor->hotSpot.v);
463   // TODO(avi): build the cursor image in Skia directly rather than going via
464   // this roundabout path.
465   cursor_info.customImage = gfx::CGImageToSkBitmap(cg_image.get());
467   InitFromCursorInfo(cursor_info);
470 void WebCursor::InitFromNSCursor(NSCursor* cursor) {
471   WebKit::WebCursorInfo cursor_info;
473   if ([cursor isEqual:[NSCursor arrowCursor]]) {
474     cursor_info.type = WebCursorInfo::TypePointer;
475   } else if ([cursor isEqual:[NSCursor IBeamCursor]]) {
476     cursor_info.type = WebCursorInfo::TypeIBeam;
477   } else if ([cursor isEqual:[NSCursor crosshairCursor]]) {
478     cursor_info.type = WebCursorInfo::TypeCross;
479   } else if ([cursor isEqual:[NSCursor pointingHandCursor]]) {
480     cursor_info.type = WebCursorInfo::TypeHand;
481   } else if ([cursor isEqual:[NSCursor resizeLeftCursor]]) {
482     cursor_info.type = WebCursorInfo::TypeWestResize;
483   } else if ([cursor isEqual:[NSCursor resizeRightCursor]]) {
484     cursor_info.type = WebCursorInfo::TypeEastResize;
485   } else if ([cursor isEqual:[NSCursor resizeLeftRightCursor]]) {
486     cursor_info.type = WebCursorInfo::TypeEastWestResize;
487   } else if ([cursor isEqual:[NSCursor resizeUpCursor]]) {
488     cursor_info.type = WebCursorInfo::TypeNorthResize;
489   } else if ([cursor isEqual:[NSCursor resizeDownCursor]]) {
490     cursor_info.type = WebCursorInfo::TypeSouthResize;
491   } else if ([cursor isEqual:[NSCursor resizeUpDownCursor]]) {
492     cursor_info.type = WebCursorInfo::TypeNorthSouthResize;
493   } else if ([cursor isEqual:[NSCursor openHandCursor]]) {
494     cursor_info.type = WebCursorInfo::TypeGrab;
495   } else if ([cursor isEqual:[NSCursor closedHandCursor]]) {
496     cursor_info.type = WebCursorInfo::TypeGrabbing;
497   } else if ([cursor isEqual:[NSCursor operationNotAllowedCursor]]) {
498     cursor_info.type = WebCursorInfo::TypeNotAllowed;
499   } else if ([NSCursor respondsToSelector:@selector(dragCopyCursor)] &&
500              [cursor isEqual:[NSCursor dragCopyCursor]]) {
501     cursor_info.type = WebCursorInfo::TypeCopy;
502   } else if ([NSCursor respondsToSelector:@selector(contextualMenuCursor)] &&
503              [cursor isEqual:[NSCursor contextualMenuCursor]]) {
504     cursor_info.type = WebCursorInfo::TypeContextMenu;
505   } else if (
506       [NSCursor respondsToSelector:@selector(IBeamCursorForVerticalLayout)] &&
507       [cursor isEqual:[NSCursor IBeamCursorForVerticalLayout]]) {
508     cursor_info.type = WebCursorInfo::TypeVerticalText;
509   } else {
510     // Also handles the [NSCursor disappearingItemCursor] case. Quick-and-dirty
511     // image conversion; TODO(avi): do better.
512     CGImageRef cg_image = nil;
513     NSImage* image = [cursor image];
514     for (id rep in [image representations]) {
515       if ([rep isKindOfClass:[NSBitmapImageRep class]]) {
516         cg_image = [rep CGImage];
517         break;
518       }
519     }
521     if (cg_image) {
522       cursor_info.type = WebCursorInfo::TypeCustom;
523       NSPoint hot_spot = [cursor hotSpot];
524       cursor_info.hotSpot = WebKit::WebPoint(hot_spot.x, hot_spot.y);
525       cursor_info.customImage = gfx::CGImageToSkBitmap(cg_image);
526     } else {
527       cursor_info.type = WebCursorInfo::TypePointer;
528     }
529   }
531   InitFromCursorInfo(cursor_info);
534 void WebCursor::InitPlatformData() {
535   return;
538 bool WebCursor::SerializePlatformData(Pickle* pickle) const {
539   return true;
542 bool WebCursor::DeserializePlatformData(PickleIterator* iter) {
543   return true;
546 bool WebCursor::IsPlatformDataEqual(const WebCursor& other) const {
547   return true;
550 void WebCursor::CleanupPlatformData() {
551   return;
554 void WebCursor::CopyPlatformData(const WebCursor& other) {
555   return;