From b294a2e73e50a8b508287f7986c195d08d66be36 Mon Sep 17 00:00:00 2001 From: "joshmoz@gmail.com" Date: Thu, 2 Aug 2007 12:08:40 -0700 Subject: [PATCH] Favicons not showing up in history menu (most of the time). Patch by Stan Shebs. b=379660 r=josh sr=pav --- widget/src/cocoa/nsMenuItemIconX.h | 5 +- widget/src/cocoa/nsMenuItemIconX.mm | 94 ++++++++++++++--------------- widget/src/cocoa/nsMenuItemX.mm | 2 +- widget/src/cocoa/nsMenuX.h | 3 + widget/src/cocoa/nsMenuX.mm | 23 ++++--- 5 files changed, 68 insertions(+), 59 deletions(-) diff --git a/widget/src/cocoa/nsMenuItemIconX.h b/widget/src/cocoa/nsMenuItemIconX.h index 81fcf528da5c..b32f7631076a 100644 --- a/widget/src/cocoa/nsMenuItemIconX.h +++ b/widget/src/cocoa/nsMenuItemIconX.h @@ -54,6 +54,7 @@ class imgIRequest; class nsIMenu; #import +#import class nsMenuItemIconX : public imgIDecoderObserver @@ -61,7 +62,8 @@ class nsMenuItemIconX : public imgIDecoderObserver public: nsMenuItemIconX(nsISupports* aMenuItem, nsIMenu* aMenu, - nsIContent* aContent); + nsIContent* aContent, + NSMenuItem* aNativeMenuItem); private: ~nsMenuItemIconX(); @@ -94,6 +96,7 @@ protected: PRUint16 mMenuItemIndex; PRPackedBool mLoadedIcon; PRPackedBool mSetIcon; + NSMenuItem* mNativeMenuItem; }; #endif // nsMenuItemIconX_h_ diff --git a/widget/src/cocoa/nsMenuItemIconX.mm b/widget/src/cocoa/nsMenuItemIconX.mm index 09fb21e75a5b..06136117b8f5 100644 --- a/widget/src/cocoa/nsMenuItemIconX.mm +++ b/widget/src/cocoa/nsMenuItemIconX.mm @@ -63,6 +63,7 @@ #include "imgIRequest.h" #include "gfxIImageFrame.h" #include "nsIImage.h" +#include "nsMenuX.h" static const PRUint32 kIconWidth = 16; @@ -85,7 +86,8 @@ NS_IMPL_ISUPPORTS2(nsMenuItemIconX, imgIContainerObserver, imgIDecoderObserver) nsMenuItemIconX::nsMenuItemIconX(nsISupports* aMenuItem, nsIMenu* aMenu, - nsIContent* aContent) + nsIContent* aContent, + NSMenuItem* aNativeMenuItem) : mContent(aContent) , mMenuItem(aMenuItem) , mMenu(aMenu) @@ -93,7 +95,9 @@ nsMenuItemIconX::nsMenuItemIconX(nsISupports* aMenuItem, , mMenuItemIndex(0) , mLoadedIcon(PR_FALSE) , mSetIcon(PR_FALSE) +, mNativeMenuItem(aNativeMenuItem) { + // printf("Creating icon for menu item %d, menu %d, native item is %d\n", aMenuItem, aMenu, aNativeMenuItem); } @@ -119,14 +123,23 @@ nsMenuItemIconX::SetupIcon() if (NS_FAILED(rv)) return rv; } + // If our native menu item isn't filled in, it's because this icon is for + // a submenu that wasn't given its native menu item until later. + if (!mNativeMenuItem) + mNativeMenuItem = (static_cast(mMenu))->GetNativeMenuItem(); + + // Still don't have one, then something is wrong, get out of here. + if (!mNativeMenuItem) { + NS_ERROR("No native menu item\n"); + return NS_ERROR_FAILURE; + } + nsCOMPtr iconURI; rv = GetIconURI(getter_AddRefs(iconURI)); if (NS_FAILED(rv)) { // There is no icon for this menu item. An icon might have been set // earlier. Clear it. - OSStatus err; - err = ::SetMenuItemIconHandle(mMenuRef, mMenuItemIndex, kMenuNoIcon, NULL); - if (err != noErr) return NS_ERROR_FAILURE; + [mNativeMenuItem setImage:nil]; return NS_OK; } @@ -248,54 +261,18 @@ nsMenuItemIconX::LoadIcon(nsIURI* aIconURI) // prevents it from jumping around or looking misaligned. static PRBool sInitializedPlaceholder; - static CGImageRef sPlaceholderIconImage; + static NSImage* sPlaceholderIconImage; if (!sInitializedPlaceholder) { sInitializedPlaceholder = PR_TRUE; - PRUint8* bitmap = (PRUint8*)malloc(kIconBytes); - - CGColorSpaceRef colorSpace = ::CGColorSpaceCreateDeviceRGB(); - - CGContextRef bitmapContext; - bitmapContext = ::CGBitmapContextCreate(bitmap, kIconWidth, kIconHeight, - kIconBitsPerComponent, - kIconBytesPerRow, - colorSpace, - kCGImageAlphaPremultipliedFirst); - if (!bitmapContext) { - free(bitmap); - ::CGColorSpaceRelease(colorSpace); - return NS_ERROR_FAILURE; - } - - CGRect iconRect = ::CGRectMake(0, 0, kIconWidth, kIconHeight); - ::CGContextClearRect(bitmapContext, iconRect); - ::CGContextRelease(bitmapContext); - - CGDataProviderRef provider; - provider = ::CGDataProviderCreateWithData(NULL, bitmap, kIconBytes, - PRAllocCGFree); - if (!provider) { - free(bitmap); - ::CGColorSpaceRelease(colorSpace); - return NS_ERROR_FAILURE; - } - - sPlaceholderIconImage = - ::CGImageCreate(kIconWidth, kIconHeight, kIconBitsPerComponent, - kIconBitsPerPixel, kIconBytesPerRow, colorSpace, - kCGImageAlphaPremultipliedFirst, provider, NULL, TRUE, - kCGRenderingIntentDefault); - ::CGColorSpaceRelease(colorSpace); - ::CGDataProviderRelease(provider); + // Note that we only create the one and reuse it forever, so this is not a leak. + sPlaceholderIconImage = [[NSImage alloc] initWithSize:NSMakeSize(kIconWidth, kIconHeight)]; } if (!sPlaceholderIconImage) return NS_ERROR_FAILURE; - OSStatus err; - err = ::SetMenuItemIconHandle(mMenuRef, mMenuItemIndex, kMenuCGImageRefType, - (Handle)sPlaceholderIconImage); - if (err != noErr) return NS_ERROR_FAILURE; + if (mNativeMenuItem) + [mNativeMenuItem setImage:sPlaceholderIconImage]; } rv = loader->LoadImage(aIconURI, nsnull, nsnull, loadGroup, this, @@ -541,11 +518,30 @@ nsMenuItemIconX::OnStopFrame(imgIRequest* aRequest, ::CGDataProviderRelease(provider); if (!iconImage) return NS_ERROR_FAILURE; - OSStatus err; - err = ::SetMenuItemIconHandle(mMenuRef, mMenuItemIndex, kMenuCGImageRefType, - (Handle)iconImage); + NSRect imageRect = NSMakeRect(0.0, 0.0, 0.0, 0.0); + CGContextRef imageContext = nil; + + // Get the image dimensions. + imageRect.size.width = kIconWidth; + imageRect.size.height = kIconHeight; + + // Create a new image to receive the Quartz image data. + NSImage* newImage = [[NSImage alloc] initWithSize:imageRect.size]; + + [newImage lockFocus]; + + // Get the Quartz context and draw. + imageContext = (CGContextRef)[[NSGraphicsContext currentContext] + graphicsPort]; + CGContextDrawImage(imageContext, *(CGRect*)&imageRect, iconImage); + [newImage unlockFocus]; + + if (!mNativeMenuItem) return NS_ERROR_FAILURE; + + [mNativeMenuItem setImage:newImage]; + + [newImage release]; ::CGImageRelease(iconImage); - if (err != noErr) return NS_ERROR_FAILURE; mLoadedIcon = PR_TRUE; mSetIcon = PR_TRUE; diff --git a/widget/src/cocoa/nsMenuItemX.mm b/widget/src/cocoa/nsMenuItemX.mm index 9de96feb36a0..319d7d2d4968 100644 --- a/widget/src/cocoa/nsMenuItemX.mm +++ b/widget/src/cocoa/nsMenuItemX.mm @@ -143,7 +143,7 @@ NS_METHOD nsMenuItemX::Create(nsIMenu* aParent, const nsString & aLabel, PRBool [mNativeMenuItem setEnabled:(BOOL)mEnabled]; } - mIcon = new nsMenuItemIconX(static_cast(this), mMenuParent, mContent); + mIcon = new nsMenuItemIconX(static_cast(this), mMenuParent, mContent, mNativeMenuItem); return NS_OK; } diff --git a/widget/src/cocoa/nsMenuX.h b/widget/src/cocoa/nsMenuX.h index 8d7622b65564..6b32db7260b2 100644 --- a/widget/src/cocoa/nsMenuX.h +++ b/widget/src/cocoa/nsMenuX.h @@ -82,6 +82,8 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSICHANGEOBSERVER + id GetNativeMenuItem(); + // nsIMenuListener methods nsEventStatus MenuItemSelected(const nsMenuEvent & aMenuEvent); nsEventStatus MenuSelected(const nsMenuEvent & aMenuEvent); @@ -160,6 +162,7 @@ protected: PRInt16 mMacMenuID; NSMenu* mMacMenu; // strong ref, we own it MenuDelegate* mMenuDelegate; // strong ref, we keep this around to get events for us + NSMenuItem* mNativeMenuItem; // strong ref, we own PRPackedBool mIsEnabled; PRPackedBool mDestroyHandlerCalled; PRPackedBool mNeedsRebuild; diff --git a/widget/src/cocoa/nsMenuX.mm b/widget/src/cocoa/nsMenuX.mm index d7aa7151f4cf..78fd49efcebd 100644 --- a/widget/src/cocoa/nsMenuX.mm +++ b/widget/src/cocoa/nsMenuX.mm @@ -106,7 +106,7 @@ NS_IMPL_ISUPPORTS4(nsMenuX, nsIMenu, nsIMenuListener, nsIChangeObserver, nsISupp nsMenuX::nsMenuX() -: mParent(nsnull), mManager(nsnull), mMacMenuID(0), mMacMenu(nil), +: mParent(nsnull), mManager(nsnull), mMacMenuID(0), mMacMenu(nil), mNativeMenuItem(nil), mIsEnabled(PR_TRUE), mDestroyHandlerCalled(PR_FALSE), mNeedsRebuild(PR_TRUE), mConstructed(PR_FALSE), mVisible(PR_TRUE), mXBLAttached(PR_FALSE) @@ -124,6 +124,7 @@ nsMenuX::~nsMenuX() [mMacMenu release]; [mMenuDelegate release]; + [mNativeMenuItem release]; // alert the change notifier we don't care no more mManager->Unregister(mMenuContent); @@ -168,7 +169,7 @@ nsMenuX::Create(nsISupports * aParent, const nsAString &aLabel, const nsAString MenuConstruct(fake, nsnull, nsnull, nsnull); if (menu) - mIcon = new nsMenuItemIconX(static_cast(this), menu, mMenuContent); + mIcon = new nsMenuItemIconX(static_cast(this), menu, mMenuContent, nsnull); return NS_OK; } @@ -296,15 +297,14 @@ nsresult nsMenuX::AddMenu(nsIMenu * aMenu) PRBool enabled; aMenu->GetEnabled(&enabled); NSString *newCocoaLabelString = MenuHelpersX::CreateTruncatedCocoaLabel(label); - NSMenuItem* newNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString action:nil keyEquivalent:@""]; - [newNativeMenuItem setEnabled:enabled]; - [mMacMenu addItem:newNativeMenuItem]; + mNativeMenuItem = [[NSMenuItem alloc] initWithTitle:newCocoaLabelString action:nil keyEquivalent:@""]; + [mNativeMenuItem setEnabled:enabled]; + [mMacMenu addItem:mNativeMenuItem]; [newCocoaLabelString release]; - [newNativeMenuItem release]; NSMenu* childMenu; if (aMenu->GetNativeData((void**)&childMenu) == NS_OK) - [newNativeMenuItem setSubmenu:childMenu]; + [mNativeMenuItem setSubmenu:childMenu]; return NS_OK; } @@ -541,7 +541,7 @@ nsEventStatus nsMenuX::MenuConstruct( gConstructingMenu = PR_FALSE; mNeedsRebuild = PR_FALSE; - // printf("Done building, mMenuItemVoidArray.Count() = %d \n", mMenuItemVoidArray.Count()); + // printf("Done building, mMenuItemsArray.Count() = %d \n", mMenuItemsArray.Count()); return nsEventStatus_eIgnore; } @@ -1031,6 +1031,13 @@ nsMenuX::GetMenuRefAndItemIndexForMenuItem(nsISupports* aMenuItem, } +id +nsMenuX::GetNativeMenuItem() +{ + return mNativeMenuItem; +} + + // // nsIChangeObserver //