175 lines
4.9 KiB
Plaintext
175 lines
4.9 KiB
Plaintext
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
/*
|
|
* Retrieves and displays icons on the macOS Touch Bar.
|
|
*/
|
|
|
|
#include "nsTouchBarInputIcon.h"
|
|
|
|
#include "MOZIconHelper.h"
|
|
#include "mozilla/dom/Document.h"
|
|
#include "nsCocoaUtils.h"
|
|
#include "nsComputedDOMStyle.h"
|
|
#include "nsContentUtils.h"
|
|
#include "nsINode.h"
|
|
#include "nsIURI.h"
|
|
#include "nsNameSpaceManager.h"
|
|
#include "nsObjCExceptions.h"
|
|
|
|
using namespace mozilla;
|
|
using mozilla::widget::IconLoader;
|
|
|
|
static const uint32_t kIconHeight = 16;
|
|
static const CGFloat kHiDPIScalingFactor = 2.0f;
|
|
|
|
nsTouchBarInputIcon::nsTouchBarInputIcon(RefPtr<Document> aDocument)
|
|
: mDocument(aDocument),
|
|
mSetIcon(false),
|
|
mButton(nil),
|
|
mShareScrubber(nil),
|
|
mPopoverItem(nil),
|
|
mIconImage(nil) {
|
|
MOZ_COUNT_CTOR(nsTouchBarInputIcon);
|
|
}
|
|
|
|
void nsTouchBarInputIcon::SetItem(TouchBarInput* aInput,
|
|
NSTouchBarItem* aItem) {
|
|
mButton = nil;
|
|
mShareScrubber = nil;
|
|
mPopoverItem = nil;
|
|
|
|
// A nil item means we are loading the icon only to cache it (e.g. pre-warming
|
|
// the Share scrubber icon before the customization palette creates its item).
|
|
if (!aInput || !aItem) {
|
|
return;
|
|
}
|
|
|
|
if ([[aInput nativeIdentifier]
|
|
isEqualToString:[TouchBarInput shareScrubberIdentifier]]) {
|
|
mShareScrubber = (NSSharingServicePickerTouchBarItem*)aItem;
|
|
} else if ([aInput baseType] == TouchBarInputBaseType::kPopover) {
|
|
mPopoverItem = (NSPopoverTouchBarItem*)aItem;
|
|
} else if ([aInput baseType] == TouchBarInputBaseType::kButton ||
|
|
[aInput baseType] == TouchBarInputBaseType::kMainButton) {
|
|
mButton = (NSButton*)[aItem view];
|
|
} else {
|
|
NS_ERROR("Incompatible Touch Bar input passed to nsTouchBarInputIcon.");
|
|
}
|
|
}
|
|
|
|
void nsTouchBarInputIcon::ApplyIcon(NSImage* aImage) {
|
|
[mButton setImage:aImage];
|
|
[mShareScrubber setButtonImage:aImage];
|
|
[mPopoverItem setCollapsedRepresentationImage:aImage];
|
|
}
|
|
|
|
nsTouchBarInputIcon::~nsTouchBarInputIcon() {
|
|
Destroy();
|
|
MOZ_COUNT_DTOR(nsTouchBarInputIcon);
|
|
}
|
|
|
|
// Called from nsTouchBar's destructor, to prevent us from outliving it
|
|
// (as might otherwise happen if calls to our imgINotificationObserver methods
|
|
// are still outstanding). nsTouchBar owns our mTouchBarInput.
|
|
void nsTouchBarInputIcon::Destroy() {
|
|
ReleaseJSObjects();
|
|
if (mIconLoader) {
|
|
mIconLoader->Destroy();
|
|
mIconLoader = nullptr;
|
|
}
|
|
|
|
mButton = nil;
|
|
mShareScrubber = nil;
|
|
mPopoverItem = nil;
|
|
|
|
[mIconImage release];
|
|
mIconImage = nil;
|
|
}
|
|
|
|
nsresult nsTouchBarInputIcon::SetupIcon(nsCOMPtr<nsIURI> aIconURI) {
|
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN;
|
|
|
|
// We might not have a document if the Touch Bar tries to update when the main
|
|
// window is closed.
|
|
if (!mDocument) {
|
|
return NS_OK;
|
|
}
|
|
|
|
// If we already decoded this exact icon, apply it synchronously. This is
|
|
// essential for the Share scrubber in the customization palette, which
|
|
// captures its image when the item is created and does not reflect a later
|
|
// asynchronous load (bug 1619333).
|
|
bool sameURI = false;
|
|
if (mIconURI && aIconURI) {
|
|
mIconURI->Equals(aIconURI, &sameURI);
|
|
}
|
|
if (mIconImage && sameURI) {
|
|
ApplyIcon(mIconImage);
|
|
mSetIcon = true;
|
|
return NS_OK;
|
|
}
|
|
|
|
// The icon changed (or this is the first load); drop any stale cached image.
|
|
if (!sameURI) {
|
|
[mIconImage release];
|
|
mIconImage = nil;
|
|
}
|
|
mIconURI = aIconURI;
|
|
|
|
if (!mIconLoader) {
|
|
mIconLoader = new IconLoader(this);
|
|
}
|
|
|
|
if (!mSetIcon) {
|
|
// Load placeholder icon.
|
|
NSSize iconSize = NSMakeSize(kIconHeight, kIconHeight);
|
|
ApplyIcon([MOZIconHelper placeholderIconWithSize:iconSize]);
|
|
}
|
|
|
|
nsresult rv =
|
|
mIconLoader->LoadIcon(aIconURI, mDocument, true /* aIsInternalIcon */);
|
|
if (NS_FAILED(rv)) {
|
|
// There is no icon for this menu item, as an error occurred while loading
|
|
// it. An icon might have been set earlier or the place holder icon may have
|
|
// been set. Clear it.
|
|
ApplyIcon(nil);
|
|
}
|
|
|
|
mSetIcon = true;
|
|
|
|
return rv;
|
|
|
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE);
|
|
}
|
|
|
|
void nsTouchBarInputIcon::ReleaseJSObjects() { mDocument = nil; }
|
|
|
|
//
|
|
// mozilla::widget::IconLoader::Listener
|
|
//
|
|
|
|
nsresult nsTouchBarInputIcon::OnComplete(imgIContainer* aImage) {
|
|
NS_OBJC_BEGIN_TRY_BLOCK_RETURN
|
|
|
|
// We ask only for the HiDPI images since all Touch Bars are Retina
|
|
// displays and we have no need for icons @1x.
|
|
NSImage* image = [MOZIconHelper
|
|
iconImageFromImageContainer:aImage
|
|
withSize:NSMakeSize(kIconHeight, kIconHeight)
|
|
svgContext:nullptr
|
|
scaleFactor:kHiDPIScalingFactor];
|
|
|
|
[image retain];
|
|
[mIconImage release];
|
|
mIconImage = image;
|
|
|
|
ApplyIcon(image);
|
|
|
|
mIconLoader->Destroy();
|
|
return NS_OK;
|
|
|
|
NS_OBJC_END_TRY_BLOCK_RETURN(NS_ERROR_FAILURE)
|
|
}
|