widget/cocoa/nsMenuItemIconX.mm

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

michael@0 1 /* -*- Mode: C++; tab-width: 2; 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 /*
michael@0 7 * Retrieves and displays icons in native menu items on Mac OS X.
michael@0 8 */
michael@0 9
michael@0 10 /* exception_defines.h defines 'try' to 'if (true)' which breaks objective-c
michael@0 11 exceptions and produces errors like: error: unexpected '@' in program'.
michael@0 12 If we define __EXCEPTIONS exception_defines.h will avoid doing this.
michael@0 13
michael@0 14 See bug 666609 for more information.
michael@0 15
michael@0 16 We use <limits> to get the libstdc++ version. */
michael@0 17 #include <limits>
michael@0 18 #if __GLIBCXX__ <= 20070719
michael@0 19 #define __EXCEPTIONS
michael@0 20 #endif
michael@0 21
michael@0 22 #include "nsMenuItemIconX.h"
michael@0 23 #include "nsObjCExceptions.h"
michael@0 24 #include "nsIContent.h"
michael@0 25 #include "nsIDocument.h"
michael@0 26 #include "nsNameSpaceManager.h"
michael@0 27 #include "nsGkAtoms.h"
michael@0 28 #include "nsIDOMElement.h"
michael@0 29 #include "nsIDOMCSSStyleDeclaration.h"
michael@0 30 #include "nsIDOMCSSValue.h"
michael@0 31 #include "nsIDOMCSSPrimitiveValue.h"
michael@0 32 #include "nsIDOMRect.h"
michael@0 33 #include "nsThreadUtils.h"
michael@0 34 #include "nsToolkit.h"
michael@0 35 #include "nsNetUtil.h"
michael@0 36 #include "imgLoader.h"
michael@0 37 #include "imgRequestProxy.h"
michael@0 38 #include "nsMenuItemX.h"
michael@0 39 #include "gfxPlatform.h"
michael@0 40 #include "imgIContainer.h"
michael@0 41 #include "nsCocoaUtils.h"
michael@0 42 #include "mozIThirdPartyUtil.h"
michael@0 43 #include "nsContentUtils.h"
michael@0 44
michael@0 45 using mozilla::gfx::SourceSurface;
michael@0 46 using mozilla::RefPtr;
michael@0 47
michael@0 48 static const uint32_t kIconWidth = 16;
michael@0 49 static const uint32_t kIconHeight = 16;
michael@0 50 static const uint32_t kIconBitsPerComponent = 8;
michael@0 51 static const uint32_t kIconComponents = 4;
michael@0 52 static const uint32_t kIconBitsPerPixel = kIconBitsPerComponent *
michael@0 53 kIconComponents;
michael@0 54 static const uint32_t kIconBytesPerRow = kIconWidth * kIconBitsPerPixel / 8;
michael@0 55 static const uint32_t kIconBytes = kIconBytesPerRow * kIconHeight;
michael@0 56
michael@0 57 typedef NS_STDCALL_FUNCPROTO(nsresult, GetRectSideMethod, nsIDOMRect,
michael@0 58 GetBottom, (nsIDOMCSSPrimitiveValue**));
michael@0 59
michael@0 60 NS_IMPL_ISUPPORTS(nsMenuItemIconX, imgINotificationObserver)
michael@0 61
michael@0 62 nsMenuItemIconX::nsMenuItemIconX(nsMenuObjectX* aMenuItem,
michael@0 63 nsIContent* aContent,
michael@0 64 NSMenuItem* aNativeMenuItem)
michael@0 65 : mContent(aContent)
michael@0 66 , mMenuObject(aMenuItem)
michael@0 67 , mLoadedIcon(false)
michael@0 68 , mSetIcon(false)
michael@0 69 , mNativeMenuItem(aNativeMenuItem)
michael@0 70 {
michael@0 71 // printf("Creating icon for menu item %d, menu %d, native item is %d\n", aMenuItem, aMenu, aNativeMenuItem);
michael@0 72 }
michael@0 73
michael@0 74 nsMenuItemIconX::~nsMenuItemIconX()
michael@0 75 {
michael@0 76 if (mIconRequest)
michael@0 77 mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
michael@0 78 }
michael@0 79
michael@0 80 // Called from mMenuObjectX's destructor, to prevent us from outliving it
michael@0 81 // (as might otherwise happen if calls to our imgINotificationObserver methods
michael@0 82 // are still outstanding). mMenuObjectX owns our nNativeMenuItem.
michael@0 83 void nsMenuItemIconX::Destroy()
michael@0 84 {
michael@0 85 if (mIconRequest) {
michael@0 86 mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
michael@0 87 mIconRequest = nullptr;
michael@0 88 }
michael@0 89 mMenuObject = nullptr;
michael@0 90 mNativeMenuItem = nil;
michael@0 91 }
michael@0 92
michael@0 93 nsresult
michael@0 94 nsMenuItemIconX::SetupIcon()
michael@0 95 {
michael@0 96 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 97
michael@0 98 // Still don't have one, then something is wrong, get out of here.
michael@0 99 if (!mNativeMenuItem) {
michael@0 100 NS_ERROR("No native menu item");
michael@0 101 return NS_ERROR_FAILURE;
michael@0 102 }
michael@0 103
michael@0 104 nsCOMPtr<nsIURI> iconURI;
michael@0 105 nsresult rv = GetIconURI(getter_AddRefs(iconURI));
michael@0 106 if (NS_FAILED(rv)) {
michael@0 107 // There is no icon for this menu item. An icon might have been set
michael@0 108 // earlier. Clear it.
michael@0 109 [mNativeMenuItem setImage:nil];
michael@0 110
michael@0 111 return NS_OK;
michael@0 112 }
michael@0 113
michael@0 114 rv = LoadIcon(iconURI);
michael@0 115 if (NS_FAILED(rv)) {
michael@0 116 // There is no icon for this menu item, as an error occurred while loading it.
michael@0 117 // An icon might have been set earlier or the place holder icon may have
michael@0 118 // been set. Clear it.
michael@0 119 [mNativeMenuItem setImage:nil];
michael@0 120 }
michael@0 121 return rv;
michael@0 122
michael@0 123 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 124 }
michael@0 125
michael@0 126 static int32_t
michael@0 127 GetDOMRectSide(nsIDOMRect* aRect, GetRectSideMethod aMethod)
michael@0 128 {
michael@0 129 nsCOMPtr<nsIDOMCSSPrimitiveValue> dimensionValue;
michael@0 130 (aRect->*aMethod)(getter_AddRefs(dimensionValue));
michael@0 131 if (!dimensionValue)
michael@0 132 return -1;
michael@0 133
michael@0 134 uint16_t primitiveType;
michael@0 135 nsresult rv = dimensionValue->GetPrimitiveType(&primitiveType);
michael@0 136 if (NS_FAILED(rv) || primitiveType != nsIDOMCSSPrimitiveValue::CSS_PX)
michael@0 137 return -1;
michael@0 138
michael@0 139 float dimension = 0;
michael@0 140 rv = dimensionValue->GetFloatValue(nsIDOMCSSPrimitiveValue::CSS_PX,
michael@0 141 &dimension);
michael@0 142 if (NS_FAILED(rv))
michael@0 143 return -1;
michael@0 144
michael@0 145 return NSToIntRound(dimension);
michael@0 146 }
michael@0 147
michael@0 148 nsresult
michael@0 149 nsMenuItemIconX::GetIconURI(nsIURI** aIconURI)
michael@0 150 {
michael@0 151 if (!mMenuObject)
michael@0 152 return NS_ERROR_FAILURE;
michael@0 153
michael@0 154 // Mac native menu items support having both a checkmark and an icon
michael@0 155 // simultaneously, but this is unheard of in the cross-platform toolkit,
michael@0 156 // seemingly because the win32 theme is unable to cope with both at once.
michael@0 157 // The downside is that it's possible to get a menu item marked with a
michael@0 158 // native checkmark and a checkmark for an icon. Head off that possibility
michael@0 159 // by pretending that no icon exists if this is a checkable menu item.
michael@0 160 if (mMenuObject->MenuObjectType() == eMenuItemObjectType) {
michael@0 161 nsMenuItemX* menuItem = static_cast<nsMenuItemX*>(mMenuObject);
michael@0 162 if (menuItem->GetMenuItemType() != eRegularMenuItemType)
michael@0 163 return NS_ERROR_FAILURE;
michael@0 164 }
michael@0 165
michael@0 166 if (!mContent)
michael@0 167 return NS_ERROR_FAILURE;
michael@0 168
michael@0 169 // First, look at the content node's "image" attribute.
michael@0 170 nsAutoString imageURIString;
michael@0 171 bool hasImageAttr = mContent->GetAttr(kNameSpaceID_None,
michael@0 172 nsGkAtoms::image,
michael@0 173 imageURIString);
michael@0 174
michael@0 175 nsresult rv;
michael@0 176 nsCOMPtr<nsIDOMCSSValue> cssValue;
michael@0 177 nsCOMPtr<nsIDOMCSSStyleDeclaration> cssStyleDecl;
michael@0 178 nsCOMPtr<nsIDOMCSSPrimitiveValue> primitiveValue;
michael@0 179 uint16_t primitiveType;
michael@0 180 if (!hasImageAttr) {
michael@0 181 // If the content node has no "image" attribute, get the
michael@0 182 // "list-style-image" property from CSS.
michael@0 183 nsCOMPtr<nsIDocument> document = mContent->GetDocument();
michael@0 184 if (!document)
michael@0 185 return NS_ERROR_FAILURE;
michael@0 186
michael@0 187 nsCOMPtr<nsPIDOMWindow> window = document->GetWindow();
michael@0 188 if (!window)
michael@0 189 return NS_ERROR_FAILURE;
michael@0 190
michael@0 191 nsCOMPtr<nsIDOMElement> domElement = do_QueryInterface(mContent);
michael@0 192 if (!domElement)
michael@0 193 return NS_ERROR_FAILURE;
michael@0 194
michael@0 195
michael@0 196 rv = window->GetComputedStyle(domElement, EmptyString(),
michael@0 197 getter_AddRefs(cssStyleDecl));
michael@0 198 if (NS_FAILED(rv))
michael@0 199 return rv;
michael@0 200
michael@0 201 NS_NAMED_LITERAL_STRING(listStyleImage, "list-style-image");
michael@0 202 rv = cssStyleDecl->GetPropertyCSSValue(listStyleImage,
michael@0 203 getter_AddRefs(cssValue));
michael@0 204 if (NS_FAILED(rv)) return rv;
michael@0 205
michael@0 206 primitiveValue = do_QueryInterface(cssValue);
michael@0 207 if (!primitiveValue) return NS_ERROR_FAILURE;
michael@0 208
michael@0 209 rv = primitiveValue->GetPrimitiveType(&primitiveType);
michael@0 210 if (NS_FAILED(rv)) return rv;
michael@0 211 if (primitiveType != nsIDOMCSSPrimitiveValue::CSS_URI)
michael@0 212 return NS_ERROR_FAILURE;
michael@0 213
michael@0 214 rv = primitiveValue->GetStringValue(imageURIString);
michael@0 215 if (NS_FAILED(rv)) return rv;
michael@0 216 }
michael@0 217
michael@0 218 // Empty the mImageRegionRect initially as the image region CSS could
michael@0 219 // have been changed and now have an error or have been removed since the
michael@0 220 // last GetIconURI call.
michael@0 221 mImageRegionRect.SetEmpty();
michael@0 222
michael@0 223 // If this menu item shouldn't have an icon, the string will be empty,
michael@0 224 // and NS_NewURI will fail.
michael@0 225 nsCOMPtr<nsIURI> iconURI;
michael@0 226 rv = NS_NewURI(getter_AddRefs(iconURI), imageURIString);
michael@0 227 if (NS_FAILED(rv)) return rv;
michael@0 228
michael@0 229 *aIconURI = iconURI;
michael@0 230 NS_ADDREF(*aIconURI);
michael@0 231
michael@0 232 if (!hasImageAttr) {
michael@0 233 // Check if the icon has a specified image region so that it can be
michael@0 234 // cropped appropriately before being displayed.
michael@0 235 NS_NAMED_LITERAL_STRING(imageRegion, "-moz-image-region");
michael@0 236 rv = cssStyleDecl->GetPropertyCSSValue(imageRegion,
michael@0 237 getter_AddRefs(cssValue));
michael@0 238 // Just return NS_OK if there if there is a failure due to no
michael@0 239 // moz-image region specified so the whole icon will be drawn anyway.
michael@0 240 if (NS_FAILED(rv)) return NS_OK;
michael@0 241
michael@0 242 primitiveValue = do_QueryInterface(cssValue);
michael@0 243 if (!primitiveValue) return NS_OK;
michael@0 244
michael@0 245 rv = primitiveValue->GetPrimitiveType(&primitiveType);
michael@0 246 if (NS_FAILED(rv)) return NS_OK;
michael@0 247 if (primitiveType != nsIDOMCSSPrimitiveValue::CSS_RECT)
michael@0 248 return NS_OK;
michael@0 249
michael@0 250 nsCOMPtr<nsIDOMRect> imageRegionRect;
michael@0 251 rv = primitiveValue->GetRectValue(getter_AddRefs(imageRegionRect));
michael@0 252 if (NS_FAILED(rv)) return NS_OK;
michael@0 253
michael@0 254 if (imageRegionRect) {
michael@0 255 // Return NS_ERROR_FAILURE if the image region is invalid so the image
michael@0 256 // is not drawn, and behavior is similar to XUL menus.
michael@0 257 int32_t bottom = GetDOMRectSide(imageRegionRect, &nsIDOMRect::GetBottom);
michael@0 258 int32_t right = GetDOMRectSide(imageRegionRect, &nsIDOMRect::GetRight);
michael@0 259 int32_t top = GetDOMRectSide(imageRegionRect, &nsIDOMRect::GetTop);
michael@0 260 int32_t left = GetDOMRectSide(imageRegionRect, &nsIDOMRect::GetLeft);
michael@0 261
michael@0 262 if (top < 0 || left < 0 || bottom <= top || right <= left)
michael@0 263 return NS_ERROR_FAILURE;
michael@0 264
michael@0 265 mImageRegionRect.SetRect(left, top, right - left, bottom - top);
michael@0 266 }
michael@0 267 }
michael@0 268
michael@0 269 return NS_OK;
michael@0 270 }
michael@0 271
michael@0 272 nsresult
michael@0 273 nsMenuItemIconX::LoadIcon(nsIURI* aIconURI)
michael@0 274 {
michael@0 275 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 276
michael@0 277 if (mIconRequest) {
michael@0 278 // Another icon request is already in flight. Kill it.
michael@0 279 mIconRequest->Cancel(NS_BINDING_ABORTED);
michael@0 280 mIconRequest = nullptr;
michael@0 281 }
michael@0 282
michael@0 283 mLoadedIcon = false;
michael@0 284
michael@0 285 if (!mContent) return NS_ERROR_FAILURE;
michael@0 286
michael@0 287 nsCOMPtr<nsIDocument> document = mContent->OwnerDoc();
michael@0 288
michael@0 289 nsCOMPtr<nsILoadGroup> loadGroup = document->GetDocumentLoadGroup();
michael@0 290 if (!loadGroup) return NS_ERROR_FAILURE;
michael@0 291
michael@0 292 nsRefPtr<imgLoader> loader = nsContentUtils::GetImgLoaderForDocument(document);
michael@0 293 if (!loader) return NS_ERROR_FAILURE;
michael@0 294
michael@0 295 if (!mSetIcon) {
michael@0 296 // Set a completely transparent 16x16 image as the icon on this menu item
michael@0 297 // as a placeholder. This keeps the menu item text displayed in the same
michael@0 298 // position that it will be displayed when the real icon is loaded, and
michael@0 299 // prevents it from jumping around or looking misaligned.
michael@0 300
michael@0 301 static bool sInitializedPlaceholder;
michael@0 302 static NSImage* sPlaceholderIconImage;
michael@0 303 if (!sInitializedPlaceholder) {
michael@0 304 sInitializedPlaceholder = true;
michael@0 305
michael@0 306 // Note that we only create the one and reuse it forever, so this is not a leak.
michael@0 307 sPlaceholderIconImage = [[NSImage alloc] initWithSize:NSMakeSize(kIconWidth, kIconHeight)];
michael@0 308 }
michael@0 309
michael@0 310 if (!sPlaceholderIconImage) return NS_ERROR_FAILURE;
michael@0 311
michael@0 312 if (mNativeMenuItem)
michael@0 313 [mNativeMenuItem setImage:sPlaceholderIconImage];
michael@0 314 }
michael@0 315
michael@0 316 nsCOMPtr<nsIURI> firstPartyIsolationURI;
michael@0 317 nsCOMPtr<mozIThirdPartyUtil> thirdPartySvc
michael@0 318 = do_GetService(THIRDPARTYUTIL_CONTRACTID);
michael@0 319 thirdPartySvc->GetFirstPartyURI(nullptr, document,
michael@0 320 getter_AddRefs(firstPartyIsolationURI));
michael@0 321
michael@0 322 // Passing in null for channelPolicy here since nsMenuItemIconX::LoadIcon is
michael@0 323 // not exposed to web content
michael@0 324 nsresult rv = loader->LoadImage(aIconURI, firstPartyIsolationURI, nullptr, nullptr, loadGroup, this,
michael@0 325 nullptr, nsIRequest::LOAD_NORMAL, nullptr,
michael@0 326 nullptr, EmptyString(), getter_AddRefs(mIconRequest));
michael@0 327 if (NS_FAILED(rv)) return rv;
michael@0 328
michael@0 329 // We need to request the icon be decoded (bug 573583, bug 705516).
michael@0 330 mIconRequest->StartDecoding();
michael@0 331
michael@0 332 return NS_OK;
michael@0 333
michael@0 334 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 335 }
michael@0 336
michael@0 337 //
michael@0 338 // imgINotificationObserver
michael@0 339 //
michael@0 340
michael@0 341 NS_IMETHODIMP
michael@0 342 nsMenuItemIconX::Notify(imgIRequest *aRequest, int32_t aType, const nsIntRect* aData)
michael@0 343 {
michael@0 344 if (aType == imgINotificationObserver::FRAME_COMPLETE) {
michael@0 345 return OnStopFrame(aRequest);
michael@0 346 }
michael@0 347
michael@0 348 if (aType == imgINotificationObserver::DECODE_COMPLETE) {
michael@0 349 if (mIconRequest && mIconRequest == aRequest) {
michael@0 350 mIconRequest->Cancel(NS_BINDING_ABORTED);
michael@0 351 mIconRequest = nullptr;
michael@0 352 }
michael@0 353 }
michael@0 354
michael@0 355 return NS_OK;
michael@0 356 }
michael@0 357
michael@0 358 nsresult
michael@0 359 nsMenuItemIconX::OnStopFrame(imgIRequest* aRequest)
michael@0 360 {
michael@0 361 NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
michael@0 362
michael@0 363 if (aRequest != mIconRequest)
michael@0 364 return NS_ERROR_FAILURE;
michael@0 365
michael@0 366 // Only support one frame.
michael@0 367 if (mLoadedIcon)
michael@0 368 return NS_OK;
michael@0 369
michael@0 370 if (!mNativeMenuItem)
michael@0 371 return NS_ERROR_FAILURE;
michael@0 372
michael@0 373 nsCOMPtr<imgIContainer> imageContainer;
michael@0 374 aRequest->GetImage(getter_AddRefs(imageContainer));
michael@0 375 if (!imageContainer) {
michael@0 376 [mNativeMenuItem setImage:nil];
michael@0 377 return NS_ERROR_FAILURE;
michael@0 378 }
michael@0 379
michael@0 380 int32_t origWidth = 0, origHeight = 0;
michael@0 381 imageContainer->GetWidth(&origWidth);
michael@0 382 imageContainer->GetHeight(&origHeight);
michael@0 383
michael@0 384 // If the image region is invalid, don't draw the image to almost match
michael@0 385 // the behavior of other platforms.
michael@0 386 if (!mImageRegionRect.IsEmpty() &&
michael@0 387 (mImageRegionRect.XMost() > origWidth ||
michael@0 388 mImageRegionRect.YMost() > origHeight)) {
michael@0 389 [mNativeMenuItem setImage:nil];
michael@0 390 return NS_ERROR_FAILURE;
michael@0 391 }
michael@0 392
michael@0 393 if (mImageRegionRect.IsEmpty()) {
michael@0 394 mImageRegionRect.SetRect(0, 0, origWidth, origHeight);
michael@0 395 }
michael@0 396
michael@0 397 RefPtr<SourceSurface> surface =
michael@0 398 imageContainer->GetFrame(imgIContainer::FRAME_CURRENT,
michael@0 399 imgIContainer::FLAG_NONE);
michael@0 400 if (!surface) {
michael@0 401 [mNativeMenuItem setImage:nil];
michael@0 402 return NS_ERROR_FAILURE;
michael@0 403 }
michael@0 404
michael@0 405 CGImageRef origImage = NULL;
michael@0 406 nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &origImage);
michael@0 407 if (NS_FAILED(rv) || !origImage) {
michael@0 408 [mNativeMenuItem setImage:nil];
michael@0 409 return NS_ERROR_FAILURE;
michael@0 410 }
michael@0 411
michael@0 412 bool createSubImage = !(mImageRegionRect.x == 0 && mImageRegionRect.y == 0 &&
michael@0 413 mImageRegionRect.width == origWidth && mImageRegionRect.height == origHeight);
michael@0 414
michael@0 415 CGImageRef finalImage = NULL;
michael@0 416 if (createSubImage) {
michael@0 417 // if mImageRegionRect is set using CSS, we need to slice a piece out of the overall
michael@0 418 // image to use as the icon
michael@0 419 finalImage = ::CGImageCreateWithImageInRect(origImage,
michael@0 420 ::CGRectMake(mImageRegionRect.x,
michael@0 421 mImageRegionRect.y,
michael@0 422 mImageRegionRect.width,
michael@0 423 mImageRegionRect.height));
michael@0 424 ::CGImageRelease(origImage);
michael@0 425 if (!finalImage) {
michael@0 426 [mNativeMenuItem setImage:nil];
michael@0 427 return NS_ERROR_FAILURE;
michael@0 428 }
michael@0 429 } else {
michael@0 430 finalImage = origImage;
michael@0 431 }
michael@0 432 // The image may not be the right size for a menu icon (16x16).
michael@0 433 // Create a new CGImage for the menu item.
michael@0 434 uint8_t* bitmap = (uint8_t*)malloc(kIconBytes);
michael@0 435
michael@0 436 CGColorSpaceRef colorSpace = ::CGColorSpaceCreateDeviceRGB();
michael@0 437
michael@0 438 CGContextRef bitmapContext = ::CGBitmapContextCreate(bitmap, kIconWidth, kIconHeight,
michael@0 439 kIconBitsPerComponent,
michael@0 440 kIconBytesPerRow,
michael@0 441 colorSpace,
michael@0 442 kCGImageAlphaPremultipliedLast);
michael@0 443 ::CGColorSpaceRelease(colorSpace);
michael@0 444 if (!bitmapContext) {
michael@0 445 ::CGImageRelease(finalImage);
michael@0 446 free(bitmap);
michael@0 447 ::CGColorSpaceRelease(colorSpace);
michael@0 448 return NS_ERROR_FAILURE;
michael@0 449 }
michael@0 450 CGRect iconRect = ::CGRectMake(0, 0, kIconWidth, kIconHeight);
michael@0 451 ::CGContextClearRect(bitmapContext, iconRect);
michael@0 452 ::CGContextDrawImage(bitmapContext, iconRect, finalImage);
michael@0 453
michael@0 454 CGImageRef iconImage = ::CGBitmapContextCreateImage(bitmapContext);
michael@0 455
michael@0 456 ::CGImageRelease(finalImage);
michael@0 457 ::CGContextRelease(bitmapContext);
michael@0 458 free(bitmap);
michael@0 459
michael@0 460 if (!iconImage) return NS_ERROR_FAILURE;
michael@0 461
michael@0 462 NSImage *newImage = nil;
michael@0 463 rv = nsCocoaUtils::CreateNSImageFromCGImage(iconImage, &newImage);
michael@0 464 if (NS_FAILED(rv) || !newImage) {
michael@0 465 [mNativeMenuItem setImage:nil];
michael@0 466 ::CGImageRelease(iconImage);
michael@0 467 return NS_ERROR_FAILURE;
michael@0 468 }
michael@0 469
michael@0 470 [mNativeMenuItem setImage:newImage];
michael@0 471
michael@0 472 [newImage release];
michael@0 473 ::CGImageRelease(iconImage);
michael@0 474
michael@0 475 mLoadedIcon = true;
michael@0 476 mSetIcon = true;
michael@0 477
michael@0 478 return NS_OK;
michael@0 479
michael@0 480 NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
michael@0 481 }

mercurial