widget/cocoa/nsCursorManager.mm

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 #include "imgIContainer.h"
     6 #include "nsCocoaUtils.h"
     7 #include "nsCursorManager.h"
     8 #include "nsObjCExceptions.h"
     9 #include <math.h>
    11 static nsCursorManager *gInstance;
    12 static CGFloat sCursorScaleFactor = 0.0f;
    13 static imgIContainer *sCursorImgContainer = nullptr;
    14 static const nsCursor sCustomCursor = eCursorCount;
    16 /*! @category nsCursorManager(PrivateMethods)
    17     Private methods for the cursor manager class.
    18 */
    19 @interface nsCursorManager(PrivateMethods)
    20 /*! @method     getCursor:
    21     @abstract   Get a reference to the native Mac representation of a cursor.
    22     @discussion Gets a reference to the Mac native implementation of a cursor.
    23                 If the cursor has been requested before, it is retreived from the cursor cache,
    24                 otherwise it is created and cached.
    25     @param      aCursor the cursor to get
    26     @result     the Mac native implementation of the cursor
    27 */
    28 - (nsMacCursor *) getCursor: (nsCursor) aCursor;
    30 /*! @method     setMacCursor:
    31  @abstract   Set the current Mac native cursor
    32  @discussion Sets the current cursor - this routine is what actually causes the cursor to change.
    33  The argument is retained and the old cursor is released.
    34  @param      aMacCursor the cursor to set
    35  @result     NS_OK
    36  */
    37 - (nsresult) setMacCursor: (nsMacCursor*) aMacCursor;
    39 /*! @method     createCursor:
    40     @abstract   Create a Mac native representation of a cursor.
    41     @discussion Creates a version of the Mac native representation of this cursor
    42     @param      aCursor the cursor to create
    43     @result     the Mac native implementation of the cursor
    44 */
    45 + (nsMacCursor *) createCursor: (enum nsCursor) aCursor;
    47 @end
    49 @implementation nsCursorManager
    51 + (nsCursorManager *) sharedInstance
    52 {
    53   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    55   if (!gInstance) {
    56     gInstance = [[nsCursorManager alloc] init];
    57   }
    58   return gInstance;
    60   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
    61 }
    63 + (void) dispose
    64 {
    65   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
    67   [gInstance release];
    68   gInstance = nil;
    70   NS_OBJC_END_TRY_ABORT_BLOCK;
    71 }
    73 + (nsMacCursor *) createCursor: (enum nsCursor) aCursor
    74 {
    75   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
    77   switch(aCursor)
    78   {
    79     SEL cursorSelector;
    80     case eCursor_standard:
    81       return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
    82     case eCursor_wait:
    83     case eCursor_spinning:
    84     {
    85       return [nsMacCursor cursorWithCursor:[NSCursor busyButClickableCursor] type:aCursor];
    86     }
    87     case eCursor_select:
    88       return [nsMacCursor cursorWithCursor:[NSCursor IBeamCursor] type:aCursor];
    89     case eCursor_hyperlink:
    90       return [nsMacCursor cursorWithCursor:[NSCursor pointingHandCursor] type:aCursor];
    91     case eCursor_crosshair:
    92       return [nsMacCursor cursorWithCursor:[NSCursor crosshairCursor] type:aCursor];
    93     case eCursor_move:
    94       return [nsMacCursor cursorWithImageNamed:@"move" hotSpot:NSMakePoint(12,12) type:aCursor];
    95     case eCursor_help:
    96       return [nsMacCursor cursorWithImageNamed:@"help" hotSpot:NSMakePoint(12,12) type:aCursor];
    97     case eCursor_copy:
    98       cursorSelector = @selector(dragCopyCursor);
    99       return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   100               [NSCursor performSelector:cursorSelector] :
   101               [NSCursor arrowCursor] type:aCursor];
   102     case eCursor_alias:
   103       cursorSelector = @selector(dragLinkCursor);
   104       return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   105               [NSCursor performSelector:cursorSelector] :
   106               [NSCursor arrowCursor] type:aCursor];
   107     case eCursor_context_menu:
   108       cursorSelector = @selector(contextualMenuCursor);
   109       return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   110               [NSCursor performSelector:cursorSelector] :
   111               [NSCursor arrowCursor] type:aCursor];
   112     case eCursor_cell:
   113       return [nsMacCursor cursorWithImageNamed:@"cell" hotSpot:NSMakePoint(12,12) type:aCursor];
   114     case eCursor_grab:
   115       return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
   116     case eCursor_grabbing:
   117       return [nsMacCursor cursorWithCursor:[NSCursor closedHandCursor] type:aCursor];
   118     case eCursor_zoom_in:
   119       return [nsMacCursor cursorWithImageNamed:@"zoomIn" hotSpot:NSMakePoint(10,10) type:aCursor];
   120     case eCursor_zoom_out:
   121       return [nsMacCursor cursorWithImageNamed:@"zoomOut" hotSpot:NSMakePoint(10,10) type:aCursor];
   122     case eCursor_vertical_text:
   123       return [nsMacCursor cursorWithImageNamed:@"vtIBeam" hotSpot:NSMakePoint(12,11) type:aCursor];
   124     case eCursor_all_scroll:
   125       return [nsMacCursor cursorWithCursor:[NSCursor openHandCursor] type:aCursor];
   126     case eCursor_not_allowed:
   127     case eCursor_no_drop:
   128       cursorSelector = @selector(operationNotAllowedCursor);
   129       return [nsMacCursor cursorWithCursor:[NSCursor respondsToSelector:cursorSelector] ?
   130               [NSCursor performSelector:cursorSelector] :
   131               [NSCursor arrowCursor] type:aCursor];
   132     // Resize Cursors:
   133     // North
   134     case eCursor_n_resize:
   135         return [nsMacCursor cursorWithCursor:[NSCursor resizeUpCursor] type:aCursor];
   136     // North East
   137     case eCursor_ne_resize:
   138         return [nsMacCursor cursorWithImageNamed:@"sizeNE" hotSpot:NSMakePoint(12,11) type:aCursor];
   139     // East
   140     case eCursor_e_resize:
   141         return [nsMacCursor cursorWithCursor:[NSCursor resizeRightCursor] type:aCursor];
   142     // South East
   143     case eCursor_se_resize:
   144         return [nsMacCursor cursorWithImageNamed:@"sizeSE" hotSpot:NSMakePoint(12,12) type:aCursor];
   145     // South
   146     case eCursor_s_resize:
   147         return [nsMacCursor cursorWithCursor:[NSCursor resizeDownCursor] type:aCursor];
   148     // South West
   149     case eCursor_sw_resize:
   150         return [nsMacCursor cursorWithImageNamed:@"sizeSW" hotSpot:NSMakePoint(10,12) type:aCursor];
   151     // West
   152     case eCursor_w_resize:
   153         return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftCursor] type:aCursor];
   154     // North West
   155     case eCursor_nw_resize:
   156         return [nsMacCursor cursorWithImageNamed:@"sizeNW" hotSpot:NSMakePoint(11,11) type:aCursor];
   157     // North & South
   158     case eCursor_ns_resize:
   159         return [nsMacCursor cursorWithCursor:[NSCursor resizeUpDownCursor] type:aCursor];
   160     // East & West
   161     case eCursor_ew_resize:
   162         return [nsMacCursor cursorWithCursor:[NSCursor resizeLeftRightCursor] type:aCursor];
   163     // North East & South West
   164     case eCursor_nesw_resize:
   165         return [nsMacCursor cursorWithImageNamed:@"sizeNESW" hotSpot:NSMakePoint(12,12) type:aCursor];
   166     // North West & South East
   167     case eCursor_nwse_resize:
   168         return [nsMacCursor cursorWithImageNamed:@"sizeNWSE" hotSpot:NSMakePoint(12,12) type:aCursor];
   169     // Column Resize
   170     case eCursor_col_resize:
   171         return [nsMacCursor cursorWithImageNamed:@"colResize" hotSpot:NSMakePoint(12,12) type:aCursor];
   172     // Row Resize
   173     case eCursor_row_resize:
   174         return [nsMacCursor cursorWithImageNamed:@"rowResize" hotSpot:NSMakePoint(12,12) type:aCursor];
   175     default:
   176         return [nsMacCursor cursorWithCursor:[NSCursor arrowCursor] type:aCursor];
   177   }
   179   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   180 }
   182 - (id) init
   183 {
   184   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   186   if ((self = [super init])) {
   187     mCursors = [[NSMutableDictionary alloc] initWithCapacity:25];
   188   }
   189   return self;
   191   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   192 }
   194 - (nsresult) setCursor: (enum nsCursor) aCursor
   195 {
   196   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   198   // Some plugins mess with our cursors and set a cursor that even
   199   // [NSCursor currentCursor] doesn't know about. In case that happens, just
   200   // reset the state.
   201   [[NSCursor currentCursor] set];
   203   nsCursor oldType = [mCurrentMacCursor type];
   204   if (oldType != aCursor) {
   205     if (aCursor == eCursor_none) {
   206       [NSCursor hide];
   207     } else if (oldType == eCursor_none) {
   208       [NSCursor unhide];
   209     }
   210   }
   211   [self setMacCursor:[self getCursor:aCursor]];
   213   // if a custom cursor was previously set, release sCursorImgContainer
   214   if (oldType == sCustomCursor) {
   215     NS_IF_RELEASE(sCursorImgContainer);
   216   }
   217   return NS_OK;
   219   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   220 }
   222 - (nsresult) setMacCursor: (nsMacCursor*) aMacCursor
   223 {
   224   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   226   if (mCurrentMacCursor != aMacCursor || ![mCurrentMacCursor isSet]) {
   227     [aMacCursor retain];
   228     [mCurrentMacCursor unset];
   229     [aMacCursor set];
   230     [mCurrentMacCursor release];
   231     mCurrentMacCursor = aMacCursor;
   232   }
   234   return NS_OK;
   236   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   237 }
   239 - (nsresult) setCursorWithImage: (imgIContainer*) aCursorImage hotSpotX: (uint32_t) aHotspotX hotSpotY: (uint32_t) aHotspotY scaleFactor: (CGFloat) scaleFactor
   240 {
   241   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
   242   // As the user moves the mouse, this gets called repeatedly with the same aCursorImage
   243   if (sCursorImgContainer == aCursorImage && sCursorScaleFactor == scaleFactor && mCurrentMacCursor) {
   244     [self setMacCursor:mCurrentMacCursor];
   245     return NS_OK;
   246   }
   248   [[NSCursor currentCursor] set];
   249   int32_t width = 0, height = 0;
   250   aCursorImage->GetWidth(&width);
   251   aCursorImage->GetHeight(&height);
   252   // prevent DoS attacks
   253   if (width > 128 || height > 128) {
   254     return NS_OK;
   255   }
   257   NSImage *cursorImage;
   258   nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(aCursorImage, imgIContainer::FRAME_FIRST, &cursorImage, scaleFactor);
   259   if (NS_FAILED(rv) || !cursorImage) {
   260     return NS_ERROR_FAILURE;
   261   }
   263   // if the hotspot is nonsensical, make it 0,0
   264   aHotspotX = (aHotspotX > (uint32_t)width - 1) ? 0 : aHotspotX;
   265   aHotspotY = (aHotspotY > (uint32_t)height - 1) ? 0 : aHotspotY;
   267   NSPoint hotSpot = ::NSMakePoint(aHotspotX, aHotspotY);
   268   [self setMacCursor:[nsMacCursor cursorWithCursor:[[NSCursor alloc] initWithImage:cursorImage hotSpot:hotSpot] type:sCustomCursor]];
   269   [cursorImage release];
   271   NS_IF_RELEASE(sCursorImgContainer);
   272   sCursorImgContainer = aCursorImage;
   273   sCursorScaleFactor = scaleFactor;
   274   NS_ADDREF(sCursorImgContainer);
   276   return NS_OK;
   278   NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
   279 }
   281 - (nsMacCursor *) getCursor: (enum nsCursor) aCursor
   282 {
   283   NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
   285   nsMacCursor * result = [mCursors objectForKey:[NSNumber numberWithInt:aCursor]];
   286   if (!result) {
   287     result = [nsCursorManager createCursor:aCursor];
   288     [mCursors setObject:result forKey:[NSNumber numberWithInt:aCursor]];
   289   }
   290   return result;
   292   NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
   293 }
   295 - (void) dealloc
   296 {
   297   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
   299   [mCurrentMacCursor unset];
   300   [mCurrentMacCursor release];
   301   [mCursors release];
   302   NS_IF_RELEASE(sCursorImgContainer);
   303   [super dealloc];
   305   NS_OBJC_END_TRY_ABORT_BLOCK;
   306 }
   308 @end

mercurial