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 aResult the resulting NSImage
@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
*/
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.

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

@ -469,7 +469,8 @@ nsresult nsCocoaUtils::CreateNSImageFromCGImage(CGImageRef aInputImage, NSImage*
}
nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, uint32_t aWhichFrame,
NSImage** aResult, CGFloat scaleFactor) {
NSImage** aResult, CGFloat scaleFactor,
bool* aIsEntirelyBlack) {
RefPtr<SourceSurface> surface;
int32_t width = 0, height = 0;
aImage->GetWidth(&width);
@ -505,7 +506,7 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, ui
NS_ENSURE_TRUE(surface, NS_ERROR_FAILURE);
CGImageRef imageRef = NULL;
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef);
nsresult rv = nsCocoaUtils::CreateCGImageFromSurface(surface, &imageRef, aIsEntirelyBlack);
if (NS_FAILED(rv) || !imageRef) {
return NS_ERROR_FAILURE;
}
@ -523,6 +524,41 @@ nsresult nsCocoaUtils::CreateNSImageFromImageContainer(imgIContainer* aImage, ui
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
void nsCocoaUtils::GetStringForNSString(const NSString* aSrc, nsAString& aDist) {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK;

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

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

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

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