зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
d77cbfd825
Коммит
2413c70932
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче