Bug 1465403 - Support loading icons @2x in macOS menu bars. r=mstange

Differential Revision: https://phabricator.services.mozilla.com/D41391

--HG--
extra : moz-landing-system : lando
This commit is contained in:
harry 2019-08-12 13:53:38 +00:00
Родитель d77cbfd825
Коммит 2413c70932
4 изменённых файлов: 97 добавлений и 38 удалений

Просмотреть файл

@ -262,10 +262,29 @@ class nsCocoaUtils {
@param aWhichFrame the frame to extract (see imgIContainer FRAME_*) @param aWhichFrame the frame to extract (see imgIContainer FRAME_*)
@param aResult the resulting NSImage @param aResult the resulting NSImage
@param scaleFactor the desired scale factor of the NSImage (2 for a retina display) @param scaleFactor the desired scale factor of the NSImage (2 for a retina display)
@param aIsEntirelyBlack an outparam that, if non-null, will be set to a
bool that indicates whether the RGB values on all
pixels are zero
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise @return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
*/ */
static nsresult CreateNSImageFromImageContainer(imgIContainer* aImage, uint32_t aWhichFrame, static nsresult CreateNSImageFromImageContainer(imgIContainer* aImage, uint32_t aWhichFrame,
NSImage** aResult, CGFloat scaleFactor); NSImage** aResult, CGFloat scaleFactor,
bool* aIsEntirelyBlack = nullptr);
/** Creates a Cocoa <code>NSImage</code> from a frame of an <code>imgIContainer</code>.
The new <code>NSImage</code> will have both a regular and HiDPI representation.
The caller owns the <code>NSImage</code>.
@param aImage the image to extract a frame from
@param aWhichFrame the frame to extract (see imgIContainer FRAME_*)
@param aResult the resulting NSImage
@param aIsEntirelyBlack an outparam that, if non-null, will be set to a
bool that indicates whether the RGB values on all
pixels are zero
@return NS_OK if the conversion worked, NS_ERROR_FAILURE otherwise
*/
static nsresult CreateDualRepresentationNSImageFromImageContainer(
imgIContainer* aImage, uint32_t aWhichFrame, NSImage** aResult,
bool* aIsEntirelyBlack = nullptr);
/** /**
* Returns nsAString for aSrc. * Returns nsAString for aSrc.

Просмотреть файл

@ -469,7 +469,8 @@ nsresult nsCocoaUtils::CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage*
} }
nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, uint32_t aWhichFrame, nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, uint32_t aWhichFrame,
NSImage** aResult, CGFloat scaleFactor) { NSImage** aResult, CGFloat scaleFactor,
bool* aIsEntirelyBlack) {
RefPtr<SourceSurface> surface; RefPtr<SourceSurface> surface;
int32_t width = 0, height = 0; int32_t width = 0, height = 0;
aImage->GetWidth(&width); aImage->GetWidth(&width);
@ -505,7 +506,7 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, ui
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE); NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
CGImageRef imageRef = NULL; CGImageRef imageRef = NULL;
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef); nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef, aIsEntirelyBlack);
if (NS_FAILED(rv) || !imageRef) { if (NS_FAILED(rv) || !imageRef) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
@ -523,6 +524,41 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, ui
return NS_OK; return NS_OK;
} }
nsresult nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(imgIContainer* aImage,
uint32_t aWhichFrame,
NSImage** aResult,
bool* aIsEntirelyBlack) {
int32_t width = 0, height = 0;
aImage->GetWidth(&width);
aImage->GetHeight(&height);
NSSize size = NSMakeSize(width, height);
*aResult = [[NSImage alloc] init];
[*aResult setSize:size];
NSImage* newRepresentation = nil;
nsresult rv = nsCocoaUtils::CreateNSImageFromImageContainer(
aImage, aWhichFrame, &newRepresentation, 1.0f, aIsEntirelyBlack);
if (NS_FAILED(rv) || !newRepresentation) {
return NS_ERROR_FAILURE;
}
[[[newRepresentation representations] objectAtIndex:0] setSize:size];
[*aResult addRepresentation:[[newRepresentation representations] objectAtIndex:0]];
[newRepresentation release];
newRepresentation = nil;
rv = nsCocoaUtils::CreateNSImageFromImageContainer(aImage, aWhichFrame, &newRepresentation, 2.0f,
aIsEntirelyBlack);
if (NS_FAILED(rv) || !newRepresentation) {
return NS_ERROR_FAILURE;
}
[[[newRepresentation representations] objectAtIndex:0] setSize:size];
[*aResult addRepresentation:[[newRepresentation representations] objectAtIndex:0]];
[newRepresentation release];
return NS_OK;
}
// static // static
void nsCocoaUtils::GetStringForNSString(const NSString* aSrc, nsAString& aDist) { void nsCocoaUtils::GetStringForNSString(const NSString* aSrc, nsAString& aDist) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;

Просмотреть файл

@ -23,9 +23,11 @@ class imgRequestProxy;
class nsIconLoaderService : public imgINotificationObserver { class nsIconLoaderService : public imgINotificationObserver {
public: public:
// If aScaleFactor is not specified, then an image with both regular and
// HiDPI representations will be loaded.
nsIconLoaderService(nsIContent* aContent, nsIntRect* aImageRegionRect, nsIconLoaderService(nsIContent* aContent, nsIntRect* aImageRegionRect,
RefPtr<nsIconLoaderObserver> aObserver, RefPtr<nsIconLoaderObserver> aObserver, uint32_t aIconHeight,
uint32_t aIconHeight, uint32_t aIconWidth); uint32_t aIconWidth, CGFloat aScaleFactor = 0.0f);
public: public:
NS_DECL_ISUPPORTS NS_DECL_ISUPPORTS
@ -55,6 +57,7 @@ class nsIconLoaderService : public imgINotificationObserver {
NSImage* mNativeIconImage; NSImage* mNativeIconImage;
uint32_t mIconHeight; uint32_t mIconHeight;
uint32_t mIconWidth; uint32_t mIconWidth;
CGFloat mScaleFactor;
RefPtr<nsIconLoaderObserver> mCompletionHandler; RefPtr<nsIconLoaderObserver> mCompletionHandler;
}; };

Просмотреть файл

@ -45,7 +45,8 @@ NS_IMPL_ISUPPORTS(nsIconLoaderService, imgINotificationObserver)
nsIconLoaderService::nsIconLoaderService(nsIContent* aContent, nsIntRect* aImageRegionRect, nsIconLoaderService::nsIconLoaderService(nsIContent* aContent, nsIntRect* aImageRegionRect,
RefPtr<nsIconLoaderObserver> aObserver, RefPtr<nsIconLoaderObserver> aObserver,
uint32_t aIconHeight, uint32_t aIconWidth) uint32_t aIconHeight, uint32_t aIconWidth,
CGFloat aScaleFactor)
: mContent(aContent), : mContent(aContent),
mContentType(nsIContentPolicy::TYPE_INTERNAL_IMAGE), mContentType(nsIContentPolicy::TYPE_INTERNAL_IMAGE),
mImageRegionRect(aImageRegionRect), mImageRegionRect(aImageRegionRect),
@ -53,6 +54,7 @@ nsIconLoaderService::nsIconLoaderService(nsIContent* aContent, nsIntRect* aImage
mNativeIconImage(nil), mNativeIconImage(nil),
mIconHeight(aIconHeight), mIconHeight(aIconHeight),
mIconWidth(aIconWidth), mIconWidth(aIconWidth),
mScaleFactor(aScaleFactor),
mCompletionHandler(aObserver) {} mCompletionHandler(aObserver) {}
nsIconLoaderService::~nsIconLoaderService() { Destroy(); } nsIconLoaderService::~nsIconLoaderService() { Destroy(); }
@ -195,45 +197,46 @@ nsresult nsIconLoaderService::OnFrameComplete(imgIRequest* aRequest) {
mImageRegionRect->SetRect(0, 0, origWidth, origHeight); mImageRegionRect->SetRect(0, 0, origWidth, origHeight);
} }
RefPtr<SourceSurface> surface = bool isEntirelyBlack = false;
imageContainer->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_SYNC_DECODE); NSImage* newImage = nil;
if (!surface) { nsresult rv;
if (mScaleFactor != 0.0f) {
rv = nsCocoaUtils::CreateNSImageFromImageContainer(imageContainer, imgIContainer::FRAME_CURRENT,
&newImage, mScaleFactor, &isEntirelyBlack);
} else {
rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
imageContainer, imgIContainer::FRAME_CURRENT, &newImage, &isEntirelyBlack);
}
if (NS_FAILED(rv) || !newImage) {
mNativeIconImage = nil; mNativeIconImage = nil;
[newImage release];
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
CGImageRef origImage = NULL; NSSize origSize = NSMakeSize(mIconWidth, mIconHeight);
bool isEntirelyBlack = false;
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &origImage, &isEntirelyBlack);
if (NS_FAILED(rv) || !origImage) {
mNativeIconImage = nil;
return NS_ERROR_FAILURE;
}
bool createSubImage = bool createSubImage =
!(mImageRegionRect->x == 0 && mImageRegionRect->y == 0 && !(mImageRegionRect->x == 0 && mImageRegionRect->y == 0 &&
mImageRegionRect->width == origWidth && mImageRegionRect->height == origHeight); mImageRegionRect->width == origWidth && mImageRegionRect->height == origHeight);
CGImageRef finalImage = origImage;
if (createSubImage) { if (createSubImage) {
// if mImageRegionRect is set using CSS, we need to slice a piece out of the overall // If mImageRegionRect is set using CSS, we need to slice a piece out of the overall
// image to use as the icon // image to use as the icon.
finalImage = ::CGImageCreateWithImageInRect( NSImage* subImage =
origImage, ::CGRectMake(mImageRegionRect->x, mImageRegionRect->y, mImageRegionRect->width, [NSImage imageWithSize:origSize
mImageRegionRect->height)); flipped:NO
::CGImageRelease(origImage); drawingHandler:^BOOL(NSRect subImageRect) {
if (!finalImage) { [newImage drawInRect:NSMakeRect(0, 0, mIconWidth, mIconHeight)
mNativeIconImage = nil; fromRect:NSMakeRect(mImageRegionRect->x, mImageRegionRect->y,
return NS_ERROR_FAILURE; mImageRegionRect->width, mImageRegionRect->height)
} operation:NSCompositeCopy
} fraction:1.0f];
return YES;
NSImage* newImage = nil; }];
rv = nsCocoaUtils::CreateNSImageFromCGImage(finalImage, &newImage); [newImage release];
if (NS_FAILED(rv) || !newImage) { newImage = [subImage retain];
mNativeIconImage = nil; subImage = nil;
::CGImageRelease(finalImage);
return NS_ERROR_FAILURE;
} }
// If all the color channels in the image are black, treat the image as a // If all the color channels in the image are black, treat the image as a
@ -244,11 +247,9 @@ nsresult nsIconLoaderService::OnFrameComplete(imgIRequest* aRequest) {
// filled with white. // filled with white.
[newImage setTemplate:isEntirelyBlack]; [newImage setTemplate:isEntirelyBlack];
[newImage setSize:NSMakeSize(mIconWidth, mIconHeight)]; [newImage setSize:origSize];
mNativeIconImage = newImage; mNativeIconImage = newImage;
::CGImageRelease(finalImage);
mLoadedIcon = true; mLoadedIcon = true;
return NS_OK; return NS_OK;