widget/cocoa/nsCocoaUtils.mm

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "gfxImageSurface.h"
michael@0 7 #include "gfxPlatform.h"
michael@0 8 #include "gfxUtils.h"
michael@0 9 #include "nsCocoaUtils.h"
michael@0 10 #include "nsChildView.h"
michael@0 11 #include "nsMenuBarX.h"
michael@0 12 #include "nsCocoaWindow.h"
michael@0 13 #include "nsCOMPtr.h"
michael@0 14 #include "nsIInterfaceRequestorUtils.h"
michael@0 15 #include "nsIAppShellService.h"
michael@0 16 #include "nsIXULWindow.h"
michael@0 17 #include "nsIBaseWindow.h"
michael@0 18 #include "nsIServiceManager.h"
michael@0 19 #include "nsMenuUtilsX.h"
michael@0 20 #include "nsToolkit.h"
michael@0 21 #include "nsCRT.h"
michael@0 22 #include "mozilla/gfx/2D.h"
michael@0 23 #include "mozilla/MiscEvents.h"
michael@0 24 #include "mozilla/Preferences.h"
michael@0 25 #include "mozilla/TextEvents.h"
michael@0 26
michael@0 27 using namespace mozilla;
michael@0 28 using namespace mozilla::widget;
michael@0 29
michael@0 30 using mozilla::gfx::BackendType;
michael@0 31 using mozilla::gfx::DataSourceSurface;
michael@0 32 using mozilla::gfx::DrawTarget;
michael@0 33 using mozilla::gfx::Factory;
michael@0 34 using mozilla::gfx::IntPoint;
michael@0 35 using mozilla::gfx::IntRect;
michael@0 36 using mozilla::gfx::IntSize;
michael@0 37 using mozilla::gfx::SurfaceFormat;
michael@0 38 using mozilla::gfx::SourceSurface;
michael@0 39
michael@0 40 static float
michael@0 41 MenuBarScreenHeight()
michael@0 42 {
michael@0 43 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
michael@0 44
michael@0 45 NSArray* allScreens = [NSScreen screens];
michael@0 46 if ([allScreens count]) {
michael@0 47 return [[allScreens objectAtIndex:0] frame].size.height;
michael@0 48 }
michael@0 49
michael@0 50 return 0.0;
michael@0 51
michael@0 52 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(0.0);
michael@0 53 }
michael@0 54
michael@0 55 float
michael@0 56 nsCocoaUtils::FlippedScreenY(float y)
michael@0 57 {
michael@0 58 return MenuBarScreenHeight() - y;
michael@0 59 }
michael@0 60
michael@0 61 NSRect nsCocoaUtils::GeckoRectToCocoaRect(const nsIntRect &geckoRect)
michael@0 62 {
michael@0 63 // We only need to change the Y coordinate by starting with the primary screen
michael@0 64 // height and subtracting the gecko Y coordinate of the bottom of the rect.
michael@0 65 return NSMakeRect(geckoRect.x,
michael@0 66 MenuBarScreenHeight() - geckoRect.YMost(),
michael@0 67 geckoRect.width,
michael@0 68 geckoRect.height);
michael@0 69 }
michael@0 70
michael@0 71 NSRect nsCocoaUtils::GeckoRectToCocoaRectDevPix(const nsIntRect &aGeckoRect,
michael@0 72 CGFloat aBackingScale)
michael@0 73 {
michael@0 74 return NSMakeRect(aGeckoRect.x / aBackingScale,
michael@0 75 MenuBarScreenHeight() - aGeckoRect.YMost() / aBackingScale,
michael@0 76 aGeckoRect.width / aBackingScale,
michael@0 77 aGeckoRect.height / aBackingScale);
michael@0 78 }
michael@0 79
michael@0 80 nsIntRect nsCocoaUtils::CocoaRectToGeckoRect(const NSRect &cocoaRect)
michael@0 81 {
michael@0 82 // We only need to change the Y coordinate by starting with the primary screen
michael@0 83 // height and subtracting both the cocoa y origin and the height of the
michael@0 84 // cocoa rect.
michael@0 85 nsIntRect rect;
michael@0 86 rect.x = NSToIntRound(cocoaRect.origin.x);
michael@0 87 rect.y = NSToIntRound(FlippedScreenY(cocoaRect.origin.y + cocoaRect.size.height));
michael@0 88 rect.width = NSToIntRound(cocoaRect.origin.x + cocoaRect.size.width) - rect.x;
michael@0 89 rect.height = NSToIntRound(FlippedScreenY(cocoaRect.origin.y)) - rect.y;
michael@0 90 return rect;
michael@0 91 }
michael@0 92
michael@0 93 nsIntRect nsCocoaUtils::CocoaRectToGeckoRectDevPix(const NSRect &aCocoaRect,
michael@0 94 CGFloat aBackingScale)
michael@0 95 {
michael@0 96 nsIntRect rect;
michael@0 97 rect.x = NSToIntRound(aCocoaRect.origin.x * aBackingScale);
michael@0 98 rect.y = NSToIntRound(FlippedScreenY(aCocoaRect.origin.y + aCocoaRect.size.height) * aBackingScale);
michael@0 99 rect.width = NSToIntRound((aCocoaRect.origin.x + aCocoaRect.size.width) * aBackingScale) - rect.x;
michael@0 100 rect.height = NSToIntRound(FlippedScreenY(aCocoaRect.origin.y) * aBackingScale) - rect.y;
michael@0 101 return rect;
michael@0 102 }
michael@0 103
michael@0 104 NSPoint nsCocoaUtils::ScreenLocationForEvent(NSEvent* anEvent)
michael@0 105 {
michael@0 106 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
michael@0 107
michael@0 108 // Don't trust mouse locations of mouse move events, see bug 443178.
michael@0 109 if (!anEvent || [anEvent type] == NSMouseMoved)
michael@0 110 return [NSEvent mouseLocation];
michael@0 111
michael@0 112 // Pin momentum scroll events to the location of the last user-controlled
michael@0 113 // scroll event.
michael@0 114 if (IsMomentumScrollEvent(anEvent))
michael@0 115 return ChildViewMouseTracker::sLastScrollEventScreenLocation;
michael@0 116
michael@0 117 return [[anEvent window] convertBaseToScreen:[anEvent locationInWindow]];
michael@0 118
michael@0 119 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0));
michael@0 120 }
michael@0 121
michael@0 122 BOOL nsCocoaUtils::IsEventOverWindow(NSEvent* anEvent, NSWindow* aWindow)
michael@0 123 {
michael@0 124 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
michael@0 125
michael@0 126 return NSPointInRect(ScreenLocationForEvent(anEvent), [aWindow frame]);
michael@0 127
michael@0 128 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NO);
michael@0 129 }
michael@0 130
michael@0 131 NSPoint nsCocoaUtils::EventLocationForWindow(NSEvent* anEvent, NSWindow* aWindow)
michael@0 132 {
michael@0 133 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_RETURN;
michael@0 134
michael@0 135 return [aWindow convertScreenToBase:ScreenLocationForEvent(anEvent)];
michael@0 136
michael@0 137 NS_OBJC_END_TRY_ABORT_BLOCK_RETURN(NSMakePoint(0.0, 0.0));
michael@0 138 }
michael@0 139
michael@0 140 BOOL nsCocoaUtils::IsMomentumScrollEvent(NSEvent* aEvent)
michael@0 141 {
michael@0 142 if ([aEvent type] != NSScrollWheel)
michael@0 143 return NO;
michael@0 144
michael@0 145 if ([aEvent respondsToSelector:@selector(momentumPhase)])
michael@0 146 return ([aEvent momentumPhase] & NSEventPhaseChanged) != 0;
michael@0 147
michael@0 148 if ([aEvent respondsToSelector:@selector(_scrollPhase)])
michael@0 149 return [aEvent _scrollPhase] != 0;
michael@0 150
michael@0 151 return NO;
michael@0 152 }
michael@0 153
michael@0 154 void nsCocoaUtils::HideOSChromeOnScreen(bool aShouldHide, NSScreen* aScreen)
michael@0 155 {
michael@0 156 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 157
michael@0 158 // Keep track of how many hiding requests have been made, so that they can
michael@0 159 // be nested.
michael@0 160 static int sMenuBarHiddenCount = 0, sDockHiddenCount = 0;
michael@0 161
michael@0 162 // Always hide the Dock, since it's not necessarily on the primary screen.
michael@0 163 sDockHiddenCount += aShouldHide ? 1 : -1;
michael@0 164 NS_ASSERTION(sMenuBarHiddenCount >= 0, "Unbalanced HideMenuAndDockForWindow calls");
michael@0 165
michael@0 166 // Only hide the menu bar if the window is on the same screen.
michael@0 167 // The menu bar is always on the first screen in the screen list.
michael@0 168 if (aScreen == [[NSScreen screens] objectAtIndex:0]) {
michael@0 169 sMenuBarHiddenCount += aShouldHide ? 1 : -1;
michael@0 170 NS_ASSERTION(sDockHiddenCount >= 0, "Unbalanced HideMenuAndDockForWindow calls");
michael@0 171 }
michael@0 172
michael@0 173 // TODO This should be upgraded to use [NSApplication setPresentationOptions:]
michael@0 174 // when support for 10.5 is dropped.
michael@0 175 if (sMenuBarHiddenCount > 0) {
michael@0 176 ::SetSystemUIMode(kUIModeAllHidden, 0);
michael@0 177 } else if (sDockHiddenCount > 0) {
michael@0 178 ::SetSystemUIMode(kUIModeContentHidden, 0);
michael@0 179 } else {
michael@0 180 ::SetSystemUIMode(kUIModeNormal, 0);
michael@0 181 }
michael@0 182
michael@0 183 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 184 }
michael@0 185
michael@0 186
michael@0 187 #define NS_APPSHELLSERVICE_CONTRACTID "@mozilla.org/appshell/appShellService;1"
michael@0 188 nsIWidget* nsCocoaUtils::GetHiddenWindowWidget()
michael@0 189 {
michael@0 190 nsCOMPtr<nsIAppShellService> appShell(do_GetService(NS_APPSHELLSERVICE_CONTRACTID));
michael@0 191 if (!appShell) {
michael@0 192 NS_WARNING("Couldn't get AppShellService in order to get hidden window ref");
michael@0 193 return nullptr;
michael@0 194 }
michael@0 195
michael@0 196 nsCOMPtr<nsIXULWindow> hiddenWindow;
michael@0 197 appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
michael@0 198 if (!hiddenWindow) {
michael@0 199 // Don't warn, this happens during shutdown, bug 358607.
michael@0 200 return nullptr;
michael@0 201 }
michael@0 202
michael@0 203 nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
michael@0 204 baseHiddenWindow = do_GetInterface(hiddenWindow);
michael@0 205 if (!baseHiddenWindow) {
michael@0 206 NS_WARNING("Couldn't get nsIBaseWindow from hidden window (nsIXULWindow)");
michael@0 207 return nullptr;
michael@0 208 }
michael@0 209
michael@0 210 nsCOMPtr<nsIWidget> hiddenWindowWidget;
michael@0 211 if (NS_FAILED(baseHiddenWindow->GetMainWidget(getter_AddRefs(hiddenWindowWidget)))) {
michael@0 212 NS_WARNING("Couldn't get nsIWidget from hidden window (nsIBaseWindow)");
michael@0 213 return nullptr;
michael@0 214 }
michael@0 215
michael@0 216 return hiddenWindowWidget;
michael@0 217 }
michael@0 218
michael@0 219 void nsCocoaUtils::PrepareForNativeAppModalDialog()
michael@0 220 {
michael@0 221 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 222
michael@0 223 // Don't do anything if this is embedding. We'll assume that if there is no hidden
michael@0 224 // window we shouldn't do anything, and that should cover the embedding case.
michael@0 225 nsMenuBarX* hiddenWindowMenuBar = nsMenuUtilsX::GetHiddenWindowMenuBar();
michael@0 226 if (!hiddenWindowMenuBar)
michael@0 227 return;
michael@0 228
michael@0 229 // First put up the hidden window menu bar so that app menu event handling is correct.
michael@0 230 hiddenWindowMenuBar->Paint();
michael@0 231
michael@0 232 NSMenu* mainMenu = [NSApp mainMenu];
michael@0 233 NS_ASSERTION([mainMenu numberOfItems] > 0, "Main menu does not have any items, something is terribly wrong!");
michael@0 234
michael@0 235 // Create new menu bar for use with modal dialog
michael@0 236 NSMenu* newMenuBar = [[NSMenu alloc] initWithTitle:@""];
michael@0 237
michael@0 238 // Swap in our app menu. Note that the event target is whatever window is up when
michael@0 239 // the app modal dialog goes up.
michael@0 240 NSMenuItem* firstMenuItem = [[mainMenu itemAtIndex:0] retain];
michael@0 241 [mainMenu removeItemAtIndex:0];
michael@0 242 [newMenuBar insertItem:firstMenuItem atIndex:0];
michael@0 243 [firstMenuItem release];
michael@0 244
michael@0 245 // Add standard edit menu
michael@0 246 [newMenuBar addItem:nsMenuUtilsX::GetStandardEditMenuItem()];
michael@0 247
michael@0 248 // Show the new menu bar
michael@0 249 [NSApp setMainMenu:newMenuBar];
michael@0 250 [newMenuBar release];
michael@0 251
michael@0 252 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 253 }
michael@0 254
michael@0 255 void nsCocoaUtils::CleanUpAfterNativeAppModalDialog()
michael@0 256 {
michael@0 257 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 258
michael@0 259 // Don't do anything if this is embedding. We'll assume that if there is no hidden
michael@0 260 // window we shouldn't do anything, and that should cover the embedding case.
michael@0 261 nsMenuBarX* hiddenWindowMenuBar = nsMenuUtilsX::GetHiddenWindowMenuBar();
michael@0 262 if (!hiddenWindowMenuBar)
michael@0 263 return;
michael@0 264
michael@0 265 NSWindow* mainWindow = [NSApp mainWindow];
michael@0 266 if (!mainWindow)
michael@0 267 hiddenWindowMenuBar->Paint();
michael@0 268 else
michael@0 269 [WindowDelegate paintMenubarForWindow:mainWindow];
michael@0 270
michael@0 271 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 272 }
michael@0 273
michael@0 274 void data_ss_release_callback(void *aDataSourceSurface,
michael@0 275 const void *data,
michael@0 276 size_t size)
michael@0 277 {
michael@0 278 if (aDataSourceSurface) {
michael@0 279 static_cast<DataSourceSurface*>(aDataSourceSurface)->Unmap();
michael@0 280 static_cast<DataSourceSurface*>(aDataSourceSurface)->Release();
michael@0 281 }
michael@0 282 }
michael@0 283
michael@0 284 nsresult nsCocoaUtils::CreateCGImageFromSurface(SourceSurface* aSurface,
michael@0 285 CGImageRef* aResult)
michael@0 286 {
michael@0 287 RefPtr<DataSourceSurface> dataSurface;
michael@0 288
michael@0 289 if (aSurface->GetFormat() == SurfaceFormat::B8G8R8A8) {
michael@0 290 dataSurface = aSurface->GetDataSurface();
michael@0 291 } else {
michael@0 292 // CGImageCreate only supports 16- and 32-bit bit-depth
michael@0 293 // Convert format to SurfaceFormat::B8G8R8A8
michael@0 294 dataSurface = gfxUtils::
michael@0 295 CopySurfaceToDataSourceSurfaceWithFormat(aSurface,
michael@0 296 SurfaceFormat::B8G8R8A8);
michael@0 297 }
michael@0 298
michael@0 299 NS_ENSURE_TRUE(dataSurface, NS_ERROR_FAILURE);
michael@0 300
michael@0 301 int32_t width = dataSurface->GetSize().width;
michael@0 302 int32_t height = dataSurface->GetSize().height;
michael@0 303 if (height < 1 || width < 1) {
michael@0 304 return NS_ERROR_FAILURE;
michael@0 305 }
michael@0 306
michael@0 307 DataSourceSurface::MappedSurface map;
michael@0 308 if (!dataSurface->Map(DataSourceSurface::MapType::READ, &map)) {
michael@0 309 return NS_ERROR_FAILURE;
michael@0 310 }
michael@0 311 // The Unmap() call happens in data_ss_release_callback
michael@0 312
michael@0 313 // Create a CGImageRef with the bits from the image, taking into account
michael@0 314 // the alpha ordering and endianness of the machine so we don't have to
michael@0 315 // touch the bits ourselves.
michael@0 316 CGDataProviderRef dataProvider = ::CGDataProviderCreateWithData(dataSurface.forget().drop(),
michael@0 317 map.mData,
michael@0 318 map.mStride * height,
michael@0 319 data_ss_release_callback);
michael@0 320 CGColorSpaceRef colorSpace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
michael@0 321 *aResult = ::CGImageCreate(width,
michael@0 322 height,
michael@0 323 8,
michael@0 324 32,
michael@0 325 map.mStride,
michael@0 326 colorSpace,
michael@0 327 kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst,
michael@0 328 dataProvider,
michael@0 329 NULL,
michael@0 330 0,
michael@0 331 kCGRenderingIntentDefault);
michael@0 332 ::CGColorSpaceRelease(colorSpace);
michael@0 333 ::CGDataProviderRelease(dataProvider);
michael@0 334 return *aResult ? NS_OK : NS_ERROR_FAILURE;
michael@0 335 }
michael@0 336
michael@0 337 nsresult nsCocoaUtils::CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage **aResult)
michael@0 338 {
michael@0 339 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 340
michael@0 341 // Be very careful when creating the NSImage that the backing NSImageRep is
michael@0 342 // exactly 1:1 with the input image. On a retina display, both [NSImage
michael@0 343 // lockFocus] and [NSImage initWithCGImage:size:] will create an image with a
michael@0 344 // 2x backing NSImageRep. This prevents NSCursor from recognizing a retina
michael@0 345 // cursor, which only occurs if pixelsWide and pixelsHigh are exactly 2x the
michael@0 346 // size of the NSImage.
michael@0 347 //
michael@0 348 // For example, if a 32x32 SVG cursor is rendered on a retina display, then
michael@0 349 // aInputImage will be 64x64. The resulting NSImage will be scaled back down
michael@0 350 // to 32x32 so it stays the correct size on the screen by changing its size
michael@0 351 // (resizing a NSImage only scales the image and doesn't resample the data).
michael@0 352 // If aInputImage is converted using [NSImage initWithCGImage:size:] then the
michael@0 353 // bitmap will be 128x128 and NSCursor won't recognize a retina cursor, since
michael@0 354 // it will expect a 64x64 bitmap.
michael@0 355
michael@0 356 int32_t width = ::CGImageGetWidth(aInputImage);
michael@0 357 int32_t height = ::CGImageGetHeight(aInputImage);
michael@0 358 NSRect imageRect = ::NSMakeRect(0.0, 0.0, width, height);
michael@0 359
michael@0 360 NSBitmapImageRep *offscreenRep = [[NSBitmapImageRep alloc]
michael@0 361 initWithBitmapDataPlanes:NULL
michael@0 362 pixelsWide:width
michael@0 363 pixelsHigh:height
michael@0 364 bitsPerSample:8
michael@0 365 samplesPerPixel:4
michael@0 366 hasAlpha:YES
michael@0 367 isPlanar:NO
michael@0 368 colorSpaceName:NSDeviceRGBColorSpace
michael@0 369 bitmapFormat:NSAlphaFirstBitmapFormat
michael@0 370 bytesPerRow:0
michael@0 371 bitsPerPixel:0];
michael@0 372
michael@0 373 NSGraphicsContext *context = [NSGraphicsContext graphicsContextWithBitmapImageRep:offscreenRep];
michael@0 374 [NSGraphicsContext saveGraphicsState];
michael@0 375 [NSGraphicsContext setCurrentContext:context];
michael@0 376
michael@0 377 // Get the Quartz context and draw.
michael@0 378 CGContextRef imageContext = (CGContextRef)[[NSGraphicsContext currentContext] graphicsPort];
michael@0 379 ::CGContextDrawImage(imageContext, *(CGRect*)&imageRect, aInputImage);
michael@0 380
michael@0 381 [NSGraphicsContext restoreGraphicsState];
michael@0 382
michael@0 383 *aResult = [[NSImage alloc] initWithSize:NSMakeSize(width, height)];
michael@0 384 [*aResult addRepresentation:offscreenRep];
michael@0 385 [offscreenRep release];
michael@0 386 return NS_OK;
michael@0 387
michael@0 388 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 389 }
michael@0 390
michael@0 391 nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer *aImage, uint32_t aWhichFrame, NSImage **aResult, CGFloat scaleFactor)
michael@0 392 {
michael@0 393 RefPtr<SourceSurface> surface;
michael@0 394 int32_t width = 0, height = 0;
michael@0 395 aImage->GetWidth(&width);
michael@0 396 aImage->GetHeight(&height);
michael@0 397
michael@0 398 // Render a vector image at the correct resolution on a retina display
michael@0 399 if (aImage->GetType() == imgIContainer::TYPE_VECTOR && scaleFactor != 1.0f) {
michael@0 400 int scaledWidth = (int)ceilf(width * scaleFactor);
michael@0 401 int scaledHeight = (int)ceilf(height * scaleFactor);
michael@0 402
michael@0 403 RefPtr<DrawTarget> drawTarget = gfxPlatform::GetPlatform()->
michael@0 404 CreateOffscreenContentDrawTarget(IntSize(scaledWidth, scaledHeight),
michael@0 405 SurfaceFormat::B8G8R8A8);
michael@0 406 if (!drawTarget) {
michael@0 407 NS_ERROR("Failed to create DrawTarget");
michael@0 408 return NS_ERROR_FAILURE;
michael@0 409 }
michael@0 410
michael@0 411 nsRefPtr<gfxContext> context = new gfxContext(drawTarget);
michael@0 412 if (!context) {
michael@0 413 NS_ERROR("Failed to create gfxContext");
michael@0 414 return NS_ERROR_FAILURE;
michael@0 415 }
michael@0 416
michael@0 417 aImage->Draw(context, GraphicsFilter::FILTER_NEAREST, gfxMatrix(),
michael@0 418 gfxRect(0.0f, 0.0f, scaledWidth, scaledHeight),
michael@0 419 nsIntRect(0, 0, width, height),
michael@0 420 nsIntSize(scaledWidth, scaledHeight),
michael@0 421 nullptr, aWhichFrame, imgIContainer::FLAG_SYNC_DECODE);
michael@0 422
michael@0 423 surface = drawTarget->Snapshot();
michael@0 424 } else {
michael@0 425 surface = aImage->GetFrame(aWhichFrame, imgIContainer::FLAG_SYNC_DECODE);
michael@0 426 }
michael@0 427
michael@0 428 NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
michael@0 429
michael@0 430 CGImageRef imageRef = NULL;
michael@0 431 nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef);
michael@0 432 if (NS_FAILED(rv) || !imageRef) {
michael@0 433 return NS_ERROR_FAILURE;
michael@0 434 }
michael@0 435
michael@0 436 rv = nsCocoaUtils::CreateNSImageFromCGImage(imageRef, aResult);
michael@0 437 if (NS_FAILED(rv) || !aResult) {
michael@0 438 return NS_ERROR_FAILURE;
michael@0 439 }
michael@0 440 ::CGImageRelease(imageRef);
michael@0 441
michael@0 442 // Ensure the image will be rendered the correct size on a retina display
michael@0 443 NSSize size = NSMakeSize(width, height);
michael@0 444 [*aResult setSize:size];
michael@0 445 [[[*aResult representations] objectAtIndex:0] setSize:size];
michael@0 446 return NS_OK;
michael@0 447 }
michael@0 448
michael@0 449 // static
michael@0 450 void
michael@0 451 nsCocoaUtils::GetStringForNSString(const NSString *aSrc, nsAString& aDist)
michael@0 452 {
michael@0 453 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 454
michael@0 455 if (!aSrc) {
michael@0 456 aDist.Truncate();
michael@0 457 return;
michael@0 458 }
michael@0 459
michael@0 460 aDist.SetLength([aSrc length]);
michael@0 461 [aSrc getCharacters: reinterpret_cast<unichar*>(aDist.BeginWriting())];
michael@0 462
michael@0 463 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 464 }
michael@0 465
michael@0 466 // static
michael@0 467 NSString*
michael@0 468 nsCocoaUtils::ToNSString(const nsAString& aString)
michael@0 469 {
michael@0 470 if (aString.IsEmpty()) {
michael@0 471 return [NSString string];
michael@0 472 }
michael@0 473 return [NSString stringWithCharacters:reinterpret_cast<const unichar*>(aString.BeginReading())
michael@0 474 length:aString.Length()];
michael@0 475 }
michael@0 476
michael@0 477 // static
michael@0 478 void
michael@0 479 nsCocoaUtils::GeckoRectToNSRect(const nsIntRect& aGeckoRect,
michael@0 480 NSRect& aOutCocoaRect)
michael@0 481 {
michael@0 482 aOutCocoaRect.origin.x = aGeckoRect.x;
michael@0 483 aOutCocoaRect.origin.y = aGeckoRect.y;
michael@0 484 aOutCocoaRect.size.width = aGeckoRect.width;
michael@0 485 aOutCocoaRect.size.height = aGeckoRect.height;
michael@0 486 }
michael@0 487
michael@0 488 // static
michael@0 489 void
michael@0 490 nsCocoaUtils::NSRectToGeckoRect(const NSRect& aCocoaRect,
michael@0 491 nsIntRect& aOutGeckoRect)
michael@0 492 {
michael@0 493 aOutGeckoRect.x = NSToIntRound(aCocoaRect.origin.x);
michael@0 494 aOutGeckoRect.y = NSToIntRound(aCocoaRect.origin.y);
michael@0 495 aOutGeckoRect.width = NSToIntRound(aCocoaRect.origin.x + aCocoaRect.size.width) - aOutGeckoRect.x;
michael@0 496 aOutGeckoRect.height = NSToIntRound(aCocoaRect.origin.y + aCocoaRect.size.height) - aOutGeckoRect.y;
michael@0 497 }
michael@0 498
michael@0 499 // static
michael@0 500 NSEvent*
michael@0 501 nsCocoaUtils::MakeNewCocoaEventWithType(NSEventType aEventType, NSEvent *aEvent)
michael@0 502 {
michael@0 503 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
michael@0 504
michael@0 505 NSEvent* newEvent =
michael@0 506 [NSEvent keyEventWithType:aEventType
michael@0 507 location:[aEvent locationInWindow]
michael@0 508 modifierFlags:[aEvent modifierFlags]
michael@0 509 timestamp:[aEvent timestamp]
michael@0 510 windowNumber:[aEvent windowNumber]
michael@0 511 context:[aEvent context]
michael@0 512 characters:[aEvent characters]
michael@0 513 charactersIgnoringModifiers:[aEvent charactersIgnoringModifiers]
michael@0 514 isARepeat:[aEvent isARepeat]
michael@0 515 keyCode:[aEvent keyCode]];
michael@0 516 return newEvent;
michael@0 517
michael@0 518 NS_OBJC_END_TRY_ABORT_BLOCK_NIL;
michael@0 519 }
michael@0 520
michael@0 521 // static
michael@0 522 void
michael@0 523 nsCocoaUtils::InitNPCocoaEvent(NPCocoaEvent* aNPCocoaEvent)
michael@0 524 {
michael@0 525 memset(aNPCocoaEvent, 0, sizeof(NPCocoaEvent));
michael@0 526 }
michael@0 527
michael@0 528 // static
michael@0 529 void
michael@0 530 nsCocoaUtils::InitPluginEvent(WidgetPluginEvent &aPluginEvent,
michael@0 531 NPCocoaEvent &aCocoaEvent)
michael@0 532 {
michael@0 533 aPluginEvent.time = PR_IntervalNow();
michael@0 534 aPluginEvent.pluginEvent = (void*)&aCocoaEvent;
michael@0 535 aPluginEvent.retargetToFocusedDocument = false;
michael@0 536 }
michael@0 537
michael@0 538 // static
michael@0 539 void
michael@0 540 nsCocoaUtils::InitInputEvent(WidgetInputEvent& aInputEvent,
michael@0 541 NSEvent* aNativeEvent)
michael@0 542 {
michael@0 543 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 544
michael@0 545 NSUInteger modifiers =
michael@0 546 aNativeEvent ? [aNativeEvent modifierFlags] : [NSEvent modifierFlags];
michael@0 547 InitInputEvent(aInputEvent, modifiers);
michael@0 548
michael@0 549 aInputEvent.time = PR_IntervalNow();
michael@0 550
michael@0 551 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 552 }
michael@0 553
michael@0 554 // static
michael@0 555 void
michael@0 556 nsCocoaUtils::InitInputEvent(WidgetInputEvent& aInputEvent,
michael@0 557 NSUInteger aModifiers)
michael@0 558 {
michael@0 559 aInputEvent.modifiers = 0;
michael@0 560 if (aModifiers & NSShiftKeyMask) {
michael@0 561 aInputEvent.modifiers |= MODIFIER_SHIFT;
michael@0 562 }
michael@0 563 if (aModifiers & NSControlKeyMask) {
michael@0 564 aInputEvent.modifiers |= MODIFIER_CONTROL;
michael@0 565 }
michael@0 566 if (aModifiers & NSAlternateKeyMask) {
michael@0 567 aInputEvent.modifiers |= MODIFIER_ALT;
michael@0 568 // Mac's option key is similar to other platforms' AltGr key.
michael@0 569 // Let's set AltGr flag when option key is pressed for consistency with
michael@0 570 // other platforms.
michael@0 571 aInputEvent.modifiers |= MODIFIER_ALTGRAPH;
michael@0 572 }
michael@0 573 if (aModifiers & NSCommandKeyMask) {
michael@0 574 aInputEvent.modifiers |= MODIFIER_META;
michael@0 575 }
michael@0 576
michael@0 577 if (aModifiers & NSAlphaShiftKeyMask) {
michael@0 578 aInputEvent.modifiers |= MODIFIER_CAPSLOCK;
michael@0 579 }
michael@0 580 // Mac doesn't have NumLock key. We can assume that NumLock is always locked
michael@0 581 // if user is using a keyboard which has numpad. Otherwise, if user is using
michael@0 582 // a keyboard which doesn't have numpad, e.g., MacBook's keyboard, we can
michael@0 583 // assume that NumLock is always unlocked.
michael@0 584 // Unfortunately, we cannot know whether current keyboard has numpad or not.
michael@0 585 // We should notify locked state only when keys in numpad are pressed.
michael@0 586 // By this, web applications may not be confused by unexpected numpad key's
michael@0 587 // key event with unlocked state.
michael@0 588 if (aModifiers & NSNumericPadKeyMask) {
michael@0 589 aInputEvent.modifiers |= MODIFIER_NUMLOCK;
michael@0 590 }
michael@0 591
michael@0 592 // Be aware, NSFunctionKeyMask is included when arrow keys, home key or some
michael@0 593 // other keys are pressed. We cannot check whether 'fn' key is pressed or
michael@0 594 // not by the flag.
michael@0 595
michael@0 596 }
michael@0 597
michael@0 598 // static
michael@0 599 UInt32
michael@0 600 nsCocoaUtils::ConvertToCarbonModifier(NSUInteger aCocoaModifier)
michael@0 601 {
michael@0 602 UInt32 carbonModifier = 0;
michael@0 603 if (aCocoaModifier & NSAlphaShiftKeyMask) {
michael@0 604 carbonModifier |= alphaLock;
michael@0 605 }
michael@0 606 if (aCocoaModifier & NSControlKeyMask) {
michael@0 607 carbonModifier |= controlKey;
michael@0 608 }
michael@0 609 if (aCocoaModifier & NSAlternateKeyMask) {
michael@0 610 carbonModifier |= optionKey;
michael@0 611 }
michael@0 612 if (aCocoaModifier & NSShiftKeyMask) {
michael@0 613 carbonModifier |= shiftKey;
michael@0 614 }
michael@0 615 if (aCocoaModifier & NSCommandKeyMask) {
michael@0 616 carbonModifier |= cmdKey;
michael@0 617 }
michael@0 618 if (aCocoaModifier & NSNumericPadKeyMask) {
michael@0 619 carbonModifier |= kEventKeyModifierNumLockMask;
michael@0 620 }
michael@0 621 if (aCocoaModifier & NSFunctionKeyMask) {
michael@0 622 carbonModifier |= kEventKeyModifierFnMask;
michael@0 623 }
michael@0 624 return carbonModifier;
michael@0 625 }
michael@0 626
michael@0 627 // While HiDPI support is not 100% complete and tested, we'll have a pref
michael@0 628 // to allow it to be turned off in case of problems (or for testing purposes).
michael@0 629
michael@0 630 // gfx.hidpi.enabled is an integer with the meaning:
michael@0 631 // <= 0 : HiDPI support is disabled
michael@0 632 // 1 : HiDPI enabled provided all screens have the same backing resolution
michael@0 633 // > 1 : HiDPI enabled even if there are a mixture of screen modes
michael@0 634
michael@0 635 // All the following code is to be removed once HiDPI work is more complete.
michael@0 636
michael@0 637 static bool sHiDPIEnabled = false;
michael@0 638 static bool sHiDPIPrefInitialized = false;
michael@0 639
michael@0 640 // static
michael@0 641 bool
michael@0 642 nsCocoaUtils::HiDPIEnabled()
michael@0 643 {
michael@0 644 if (!sHiDPIPrefInitialized) {
michael@0 645 sHiDPIPrefInitialized = true;
michael@0 646
michael@0 647 int prefSetting = Preferences::GetInt("gfx.hidpi.enabled", 1);
michael@0 648 if (prefSetting <= 0) {
michael@0 649 return false;
michael@0 650 }
michael@0 651
michael@0 652 // prefSetting is at least 1, need to check attached screens...
michael@0 653
michael@0 654 int scaleFactors = 0; // used as a bitset to track the screen types found
michael@0 655 NSEnumerator *screenEnum = [[NSScreen screens] objectEnumerator];
michael@0 656 while (NSScreen *screen = [screenEnum nextObject]) {
michael@0 657 NSDictionary *desc = [screen deviceDescription];
michael@0 658 if ([desc objectForKey:NSDeviceIsScreen] == nil) {
michael@0 659 continue;
michael@0 660 }
michael@0 661 CGFloat scale =
michael@0 662 [screen respondsToSelector:@selector(backingScaleFactor)] ?
michael@0 663 [screen backingScaleFactor] : 1.0;
michael@0 664 // Currently, we only care about differentiating "1.0" and "2.0",
michael@0 665 // so we set one of the two low bits to record which.
michael@0 666 if (scale > 1.0) {
michael@0 667 scaleFactors |= 2;
michael@0 668 } else {
michael@0 669 scaleFactors |= 1;
michael@0 670 }
michael@0 671 }
michael@0 672
michael@0 673 // Now scaleFactors will be:
michael@0 674 // 0 if no screens (supporting backingScaleFactor) found
michael@0 675 // 1 if only lo-DPI screens
michael@0 676 // 2 if only hi-DPI screens
michael@0 677 // 3 if both lo- and hi-DPI screens
michael@0 678 // We'll enable HiDPI support if there's only a single screen type,
michael@0 679 // OR if the pref setting is explicitly greater than 1.
michael@0 680 sHiDPIEnabled = (scaleFactors <= 2) || (prefSetting > 1);
michael@0 681 }
michael@0 682
michael@0 683 return sHiDPIEnabled;
michael@0 684 }
michael@0 685
michael@0 686 void
michael@0 687 nsCocoaUtils::GetCommandsFromKeyEvent(NSEvent* aEvent,
michael@0 688 nsTArray<KeyBindingsCommand>& aCommands)
michael@0 689 {
michael@0 690 NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
michael@0 691
michael@0 692 MOZ_ASSERT(aEvent);
michael@0 693
michael@0 694 static NativeKeyBindingsRecorder* sNativeKeyBindingsRecorder;
michael@0 695 if (!sNativeKeyBindingsRecorder) {
michael@0 696 sNativeKeyBindingsRecorder = [NativeKeyBindingsRecorder new];
michael@0 697 }
michael@0 698
michael@0 699 [sNativeKeyBindingsRecorder startRecording:aCommands];
michael@0 700
michael@0 701 // This will trigger 0 - N calls to doCommandBySelector: and insertText:
michael@0 702 [sNativeKeyBindingsRecorder
michael@0 703 interpretKeyEvents:[NSArray arrayWithObject:aEvent]];
michael@0 704
michael@0 705 NS_OBJC_END_TRY_ABORT_BLOCK;
michael@0 706 }
michael@0 707
michael@0 708 @implementation NativeKeyBindingsRecorder
michael@0 709
michael@0 710 - (void)startRecording:(nsTArray<KeyBindingsCommand>&)aCommands
michael@0 711 {
michael@0 712 mCommands = &aCommands;
michael@0 713 mCommands->Clear();
michael@0 714 }
michael@0 715
michael@0 716 - (void)doCommandBySelector:(SEL)aSelector
michael@0 717 {
michael@0 718 KeyBindingsCommand command = {
michael@0 719 aSelector,
michael@0 720 nil
michael@0 721 };
michael@0 722
michael@0 723 mCommands->AppendElement(command);
michael@0 724 }
michael@0 725
michael@0 726 - (void)insertText:(id)aString
michael@0 727 {
michael@0 728 KeyBindingsCommand command = {
michael@0 729 @selector(insertText:),
michael@0 730 aString
michael@0 731 };
michael@0 732
michael@0 733 mCommands->AppendElement(command);
michael@0 734 }
michael@0 735
michael@0 736 @end // NativeKeyBindingsRecorder
michael@0 737
michael@0 738 struct KeyConversionData
michael@0 739 {
michael@0 740 const char* str;
michael@0 741 size_t strLength;
michael@0 742 uint32_t geckoKeyCode;
michael@0 743 uint32_t charCode;
michael@0 744 };
michael@0 745
michael@0 746 static const KeyConversionData gKeyConversions[] = {
michael@0 747
michael@0 748 #define KEYCODE_ENTRY(aStr, aCode) \
michael@0 749 {#aStr, sizeof(#aStr) - 1, NS_##aStr, aCode}
michael@0 750
michael@0 751 // Some keycodes may have different name in nsIDOMKeyEvent from its key name.
michael@0 752 #define KEYCODE_ENTRY2(aStr, aNSName, aCode) \
michael@0 753 {#aStr, sizeof(#aStr) - 1, NS_##aNSName, aCode}
michael@0 754
michael@0 755 KEYCODE_ENTRY(VK_CANCEL, 0x001B),
michael@0 756 KEYCODE_ENTRY(VK_DELETE, NSDeleteFunctionKey),
michael@0 757 KEYCODE_ENTRY(VK_BACK, NSBackspaceCharacter),
michael@0 758 KEYCODE_ENTRY2(VK_BACK_SPACE, VK_BACK, NSBackspaceCharacter),
michael@0 759 KEYCODE_ENTRY(VK_TAB, NSTabCharacter),
michael@0 760 KEYCODE_ENTRY(VK_CLEAR, NSClearLineFunctionKey),
michael@0 761 KEYCODE_ENTRY(VK_RETURN, NSEnterCharacter),
michael@0 762 KEYCODE_ENTRY(VK_SHIFT, 0),
michael@0 763 KEYCODE_ENTRY(VK_CONTROL, 0),
michael@0 764 KEYCODE_ENTRY(VK_ALT, 0),
michael@0 765 KEYCODE_ENTRY(VK_PAUSE, NSPauseFunctionKey),
michael@0 766 KEYCODE_ENTRY(VK_CAPS_LOCK, 0),
michael@0 767 KEYCODE_ENTRY(VK_ESCAPE, 0),
michael@0 768 KEYCODE_ENTRY(VK_SPACE, ' '),
michael@0 769 KEYCODE_ENTRY(VK_PAGE_UP, NSPageUpFunctionKey),
michael@0 770 KEYCODE_ENTRY(VK_PAGE_DOWN, NSPageDownFunctionKey),
michael@0 771 KEYCODE_ENTRY(VK_END, NSEndFunctionKey),
michael@0 772 KEYCODE_ENTRY(VK_HOME, NSHomeFunctionKey),
michael@0 773 KEYCODE_ENTRY(VK_LEFT, NSLeftArrowFunctionKey),
michael@0 774 KEYCODE_ENTRY(VK_UP, NSUpArrowFunctionKey),
michael@0 775 KEYCODE_ENTRY(VK_RIGHT, NSRightArrowFunctionKey),
michael@0 776 KEYCODE_ENTRY(VK_DOWN, NSDownArrowFunctionKey),
michael@0 777 KEYCODE_ENTRY(VK_PRINTSCREEN, NSPrintScreenFunctionKey),
michael@0 778 KEYCODE_ENTRY(VK_INSERT, NSInsertFunctionKey),
michael@0 779 KEYCODE_ENTRY(VK_HELP, NSHelpFunctionKey),
michael@0 780 KEYCODE_ENTRY(VK_0, '0'),
michael@0 781 KEYCODE_ENTRY(VK_1, '1'),
michael@0 782 KEYCODE_ENTRY(VK_2, '2'),
michael@0 783 KEYCODE_ENTRY(VK_3, '3'),
michael@0 784 KEYCODE_ENTRY(VK_4, '4'),
michael@0 785 KEYCODE_ENTRY(VK_5, '5'),
michael@0 786 KEYCODE_ENTRY(VK_6, '6'),
michael@0 787 KEYCODE_ENTRY(VK_7, '7'),
michael@0 788 KEYCODE_ENTRY(VK_8, '8'),
michael@0 789 KEYCODE_ENTRY(VK_9, '9'),
michael@0 790 KEYCODE_ENTRY(VK_SEMICOLON, ':'),
michael@0 791 KEYCODE_ENTRY(VK_EQUALS, '='),
michael@0 792 KEYCODE_ENTRY(VK_A, 'A'),
michael@0 793 KEYCODE_ENTRY(VK_B, 'B'),
michael@0 794 KEYCODE_ENTRY(VK_C, 'C'),
michael@0 795 KEYCODE_ENTRY(VK_D, 'D'),
michael@0 796 KEYCODE_ENTRY(VK_E, 'E'),
michael@0 797 KEYCODE_ENTRY(VK_F, 'F'),
michael@0 798 KEYCODE_ENTRY(VK_G, 'G'),
michael@0 799 KEYCODE_ENTRY(VK_H, 'H'),
michael@0 800 KEYCODE_ENTRY(VK_I, 'I'),
michael@0 801 KEYCODE_ENTRY(VK_J, 'J'),
michael@0 802 KEYCODE_ENTRY(VK_K, 'K'),
michael@0 803 KEYCODE_ENTRY(VK_L, 'L'),
michael@0 804 KEYCODE_ENTRY(VK_M, 'M'),
michael@0 805 KEYCODE_ENTRY(VK_N, 'N'),
michael@0 806 KEYCODE_ENTRY(VK_O, 'O'),
michael@0 807 KEYCODE_ENTRY(VK_P, 'P'),
michael@0 808 KEYCODE_ENTRY(VK_Q, 'Q'),
michael@0 809 KEYCODE_ENTRY(VK_R, 'R'),
michael@0 810 KEYCODE_ENTRY(VK_S, 'S'),
michael@0 811 KEYCODE_ENTRY(VK_T, 'T'),
michael@0 812 KEYCODE_ENTRY(VK_U, 'U'),
michael@0 813 KEYCODE_ENTRY(VK_V, 'V'),
michael@0 814 KEYCODE_ENTRY(VK_W, 'W'),
michael@0 815 KEYCODE_ENTRY(VK_X, 'X'),
michael@0 816 KEYCODE_ENTRY(VK_Y, 'Y'),
michael@0 817 KEYCODE_ENTRY(VK_Z, 'Z'),
michael@0 818 KEYCODE_ENTRY(VK_CONTEXT_MENU, NSMenuFunctionKey),
michael@0 819 KEYCODE_ENTRY(VK_NUMPAD0, '0'),
michael@0 820 KEYCODE_ENTRY(VK_NUMPAD1, '1'),
michael@0 821 KEYCODE_ENTRY(VK_NUMPAD2, '2'),
michael@0 822 KEYCODE_ENTRY(VK_NUMPAD3, '3'),
michael@0 823 KEYCODE_ENTRY(VK_NUMPAD4, '4'),
michael@0 824 KEYCODE_ENTRY(VK_NUMPAD5, '5'),
michael@0 825 KEYCODE_ENTRY(VK_NUMPAD6, '6'),
michael@0 826 KEYCODE_ENTRY(VK_NUMPAD7, '7'),
michael@0 827 KEYCODE_ENTRY(VK_NUMPAD8, '8'),
michael@0 828 KEYCODE_ENTRY(VK_NUMPAD9, '9'),
michael@0 829 KEYCODE_ENTRY(VK_MULTIPLY, '*'),
michael@0 830 KEYCODE_ENTRY(VK_ADD, '+'),
michael@0 831 KEYCODE_ENTRY(VK_SEPARATOR, 0),
michael@0 832 KEYCODE_ENTRY(VK_SUBTRACT, '-'),
michael@0 833 KEYCODE_ENTRY(VK_DECIMAL, '.'),
michael@0 834 KEYCODE_ENTRY(VK_DIVIDE, '/'),
michael@0 835 KEYCODE_ENTRY(VK_F1, NSF1FunctionKey),
michael@0 836 KEYCODE_ENTRY(VK_F2, NSF2FunctionKey),
michael@0 837 KEYCODE_ENTRY(VK_F3, NSF3FunctionKey),
michael@0 838 KEYCODE_ENTRY(VK_F4, NSF4FunctionKey),
michael@0 839 KEYCODE_ENTRY(VK_F5, NSF5FunctionKey),
michael@0 840 KEYCODE_ENTRY(VK_F6, NSF6FunctionKey),
michael@0 841 KEYCODE_ENTRY(VK_F7, NSF7FunctionKey),
michael@0 842 KEYCODE_ENTRY(VK_F8, NSF8FunctionKey),
michael@0 843 KEYCODE_ENTRY(VK_F9, NSF9FunctionKey),
michael@0 844 KEYCODE_ENTRY(VK_F10, NSF10FunctionKey),
michael@0 845 KEYCODE_ENTRY(VK_F11, NSF11FunctionKey),
michael@0 846 KEYCODE_ENTRY(VK_F12, NSF12FunctionKey),
michael@0 847 KEYCODE_ENTRY(VK_F13, NSF13FunctionKey),
michael@0 848 KEYCODE_ENTRY(VK_F14, NSF14FunctionKey),
michael@0 849 KEYCODE_ENTRY(VK_F15, NSF15FunctionKey),
michael@0 850 KEYCODE_ENTRY(VK_F16, NSF16FunctionKey),
michael@0 851 KEYCODE_ENTRY(VK_F17, NSF17FunctionKey),
michael@0 852 KEYCODE_ENTRY(VK_F18, NSF18FunctionKey),
michael@0 853 KEYCODE_ENTRY(VK_F19, NSF19FunctionKey),
michael@0 854 KEYCODE_ENTRY(VK_F20, NSF20FunctionKey),
michael@0 855 KEYCODE_ENTRY(VK_F21, NSF21FunctionKey),
michael@0 856 KEYCODE_ENTRY(VK_F22, NSF22FunctionKey),
michael@0 857 KEYCODE_ENTRY(VK_F23, NSF23FunctionKey),
michael@0 858 KEYCODE_ENTRY(VK_F24, NSF24FunctionKey),
michael@0 859 KEYCODE_ENTRY(VK_NUM_LOCK, NSClearLineFunctionKey),
michael@0 860 KEYCODE_ENTRY(VK_SCROLL_LOCK, NSScrollLockFunctionKey),
michael@0 861 KEYCODE_ENTRY(VK_COMMA, ','),
michael@0 862 KEYCODE_ENTRY(VK_PERIOD, '.'),
michael@0 863 KEYCODE_ENTRY(VK_SLASH, '/'),
michael@0 864 KEYCODE_ENTRY(VK_BACK_QUOTE, '`'),
michael@0 865 KEYCODE_ENTRY(VK_OPEN_BRACKET, '['),
michael@0 866 KEYCODE_ENTRY(VK_BACK_SLASH, '\\'),
michael@0 867 KEYCODE_ENTRY(VK_CLOSE_BRACKET, ']'),
michael@0 868 KEYCODE_ENTRY(VK_QUOTE, '\'')
michael@0 869
michael@0 870 #undef KEYCODE_ENTRY
michael@0 871
michael@0 872 };
michael@0 873
michael@0 874 uint32_t
michael@0 875 nsCocoaUtils::ConvertGeckoNameToMacCharCode(const nsAString& aKeyCodeName)
michael@0 876 {
michael@0 877 if (aKeyCodeName.IsEmpty()) {
michael@0 878 return 0;
michael@0 879 }
michael@0 880
michael@0 881 nsAutoCString keyCodeName;
michael@0 882 keyCodeName.AssignWithConversion(aKeyCodeName);
michael@0 883 // We want case-insensitive comparison with data stored as uppercase.
michael@0 884 ToUpperCase(keyCodeName);
michael@0 885
michael@0 886 uint32_t keyCodeNameLength = keyCodeName.Length();
michael@0 887 const char* keyCodeNameStr = keyCodeName.get();
michael@0 888 for (uint16_t i = 0; i < ArrayLength(gKeyConversions); ++i) {
michael@0 889 if (keyCodeNameLength == gKeyConversions[i].strLength &&
michael@0 890 nsCRT::strcmp(gKeyConversions[i].str, keyCodeNameStr) == 0) {
michael@0 891 return gKeyConversions[i].charCode;
michael@0 892 }
michael@0 893 }
michael@0 894
michael@0 895 return 0;
michael@0 896 }
michael@0 897
michael@0 898 uint32_t
michael@0 899 nsCocoaUtils::ConvertGeckoKeyCodeToMacCharCode(uint32_t aKeyCode)
michael@0 900 {
michael@0 901 if (!aKeyCode) {
michael@0 902 return 0;
michael@0 903 }
michael@0 904
michael@0 905 for (uint16_t i = 0; i < ArrayLength(gKeyConversions); ++i) {
michael@0 906 if (gKeyConversions[i].geckoKeyCode == aKeyCode) {
michael@0 907 return gKeyConversions[i].charCode;
michael@0 908 }
michael@0 909 }
michael@0 910
michael@0 911 return 0;
michael@0 912 }

mercurial