2007-04-22 05:42:17 +04:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 15:12:37 +04:00
|
|
|
/* 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/. */
|
2007-04-22 05:42:17 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieves and displays icons in native menu items on Mac OS X.
|
|
|
|
*/
|
|
|
|
|
2012-11-16 22:24:58 +04:00
|
|
|
/* exception_defines.h defines 'try' to 'if (true)' which breaks objective-c
|
|
|
|
exceptions and produces errors like: error: unexpected '@' in program'.
|
|
|
|
If we define __EXCEPTIONS exception_defines.h will avoid doing this.
|
|
|
|
|
|
|
|
See bug 666609 for more information.
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2012-11-16 22:24:58 +04:00
|
|
|
We use <limits> to get the libstdc++ version. */
|
|
|
|
#include <limits>
|
|
|
|
#if __GLIBCXX__ <= 20070719
|
2019-01-21 20:18:16 +03:00
|
|
|
# ifndef __EXCEPTIONS
|
|
|
|
# define __EXCEPTIONS
|
|
|
|
# endif
|
2016-03-07 05:10:17 +03:00
|
|
|
#endif
|
2012-11-16 22:24:58 +04:00
|
|
|
|
2019-01-02 16:05:23 +03:00
|
|
|
#include "mozilla/dom/Document.h"
|
2010-03-13 17:39:55 +03:00
|
|
|
#include "nsCocoaUtils.h"
|
2019-07-10 04:23:45 +03:00
|
|
|
#include "nsComputedDOMStyle.h"
|
2012-06-26 08:20:12 +04:00
|
|
|
#include "nsContentUtils.h"
|
2019-07-10 04:23:45 +03:00
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsIContent.h"
|
2014-08-20 01:49:38 +04:00
|
|
|
#include "nsIContentPolicy.h"
|
2019-07-10 04:23:45 +03:00
|
|
|
#include "nsMenuItemX.h"
|
|
|
|
#include "nsMenuItemIconX.h"
|
|
|
|
#include "nsNameSpaceManager.h"
|
|
|
|
#include "nsObjCExceptions.h"
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2018-11-14 20:03:36 +03:00
|
|
|
using namespace mozilla;
|
|
|
|
|
2015-10-27 00:37:32 +03:00
|
|
|
using mozilla::dom::Element;
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2019-07-10 04:23:45 +03:00
|
|
|
static const uint32_t kIconSize = 16;
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
nsMenuItemIconX::nsMenuItemIconX(nsMenuObjectX* aMenuItem, nsIContent* aContent,
|
|
|
|
NSMenuItem* aNativeMenuItem)
|
|
|
|
: mContent(aContent),
|
2019-09-06 22:03:15 +03:00
|
|
|
mTriggeringPrincipal(aContent->NodePrincipal()),
|
2019-01-21 20:18:16 +03:00
|
|
|
mContentType(nsIContentPolicy::TYPE_INTERNAL_IMAGE),
|
|
|
|
mMenuObject(aMenuItem),
|
|
|
|
mSetIcon(false),
|
|
|
|
mNativeMenuItem(aNativeMenuItem) {
|
2019-07-10 04:23:45 +03:00
|
|
|
MOZ_COUNT_CTOR(nsMenuItemIconX);
|
2007-04-22 05:42:17 +04:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
nsMenuItemIconX::~nsMenuItemIconX() {
|
2019-07-10 04:23:45 +03:00
|
|
|
Destroy();
|
|
|
|
MOZ_COUNT_DTOR(nsMenuItemIconX);
|
2007-04-22 05:42:17 +04:00
|
|
|
}
|
|
|
|
|
2009-07-07 00:59:46 +04:00
|
|
|
// Called from mMenuObjectX's destructor, to prevent us from outliving it
|
2012-12-18 20:37:15 +04:00
|
|
|
// (as might otherwise happen if calls to our imgINotificationObserver methods
|
2019-09-06 22:03:15 +03:00
|
|
|
// are still outstanding). mMenuObjectX owns our nNativeMenuItem.
|
2019-01-21 20:18:16 +03:00
|
|
|
void nsMenuItemIconX::Destroy() {
|
2019-07-10 04:23:45 +03:00
|
|
|
if (mIconLoader) {
|
|
|
|
mIconLoader->Destroy();
|
|
|
|
mIconLoader = nullptr;
|
2009-07-07 00:59:46 +04:00
|
|
|
}
|
2019-09-06 22:03:15 +03:00
|
|
|
|
2012-07-30 18:20:58 +04:00
|
|
|
mMenuObject = nullptr;
|
2009-07-07 00:59:46 +04:00
|
|
|
mNativeMenuItem = nil;
|
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
nsresult nsMenuItemIconX::SetupIcon() {
|
2008-02-21 02:47:05 +03:00
|
|
|
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
|
|
|
|
|
2007-08-02 23:08:40 +04:00
|
|
|
// Still don't have one, then something is wrong, get out of here.
|
|
|
|
if (!mNativeMenuItem) {
|
2010-06-18 00:28:38 +04:00
|
|
|
NS_ERROR("No native menu item");
|
2007-08-02 23:08:40 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
2007-04-22 05:42:17 +04:00
|
|
|
nsCOMPtr<nsIURI> iconURI;
|
2008-06-28 11:55:30 +04:00
|
|
|
nsresult rv = GetIconURI(getter_AddRefs(iconURI));
|
2007-04-22 05:42:17 +04:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
// There is no icon for this menu item. An icon might have been set
|
|
|
|
// earlier. Clear it.
|
2007-08-02 23:08:40 +04:00
|
|
|
[mNativeMenuItem setImage:nil];
|
2007-04-22 05:42:17 +04:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-09-06 22:03:15 +03:00
|
|
|
if (!mSetIcon) {
|
|
|
|
// Set a completely transparent 16x16 image as the icon on this menu item
|
|
|
|
// as a placeholder. This keeps the menu item text displayed in the same
|
|
|
|
// position that it will be displayed when the real icon is loaded, and
|
|
|
|
// prevents it from jumping around or looking misaligned.
|
|
|
|
|
|
|
|
static bool sInitializedPlaceholder;
|
|
|
|
static NSImage* sPlaceholderIconImage;
|
|
|
|
if (!sInitializedPlaceholder) {
|
|
|
|
sInitializedPlaceholder = true;
|
|
|
|
|
|
|
|
// Note that we only create the one and reuse it forever, so this is not a leak.
|
|
|
|
sPlaceholderIconImage = [[NSImage alloc] initWithSize:NSMakeSize(kIconSize, kIconSize)];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sPlaceholderIconImage) {
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mNativeMenuItem) {
|
|
|
|
[mNativeMenuItem setImage:sPlaceholderIconImage];
|
|
|
|
}
|
|
|
|
}
|
2019-07-10 04:23:45 +03:00
|
|
|
if (!mIconLoader) {
|
|
|
|
mIconLoader = new nsIconLoaderService(mContent, &mImageRegionRect, this, kIconSize, kIconSize);
|
|
|
|
if (!mIconLoader) {
|
|
|
|
return NS_ERROR_OUT_OF_MEMORY;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rv = mIconLoader->LoadIcon(iconURI);
|
2009-12-12 01:09:11 +03:00
|
|
|
if (NS_FAILED(rv)) {
|
2010-05-13 16:19:50 +04:00
|
|
|
// There is no icon for this menu item, as an error occurred while loading it.
|
2009-12-12 01:09:11 +03:00
|
|
|
// An icon might have been set earlier or the place holder icon may have
|
|
|
|
// been set. Clear it.
|
|
|
|
[mNativeMenuItem setImage:nil];
|
|
|
|
}
|
2019-07-10 04:23:45 +03:00
|
|
|
|
|
|
|
mSetIcon = true;
|
|
|
|
|
2009-12-12 01:09:11 +03:00
|
|
|
return rv;
|
2008-02-21 02:47:05 +03:00
|
|
|
|
|
|
|
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
|
2007-04-22 05:42:17 +04:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
nsresult nsMenuItemIconX::GetIconURI(nsIURI** aIconURI) {
|
|
|
|
if (!mMenuObject) return NS_ERROR_FAILURE;
|
2009-07-07 00:59:46 +04:00
|
|
|
|
2007-04-22 05:42:17 +04:00
|
|
|
// Mac native menu items support having both a checkmark and an icon
|
|
|
|
// simultaneously, but this is unheard of in the cross-platform toolkit,
|
|
|
|
// seemingly because the win32 theme is unable to cope with both at once.
|
|
|
|
// The downside is that it's possible to get a menu item marked with a
|
|
|
|
// native checkmark and a checkmark for an icon. Head off that possibility
|
|
|
|
// by pretending that no icon exists if this is a checkable menu item.
|
2008-06-28 11:55:30 +04:00
|
|
|
if (mMenuObject->MenuObjectType() == eMenuItemObjectType) {
|
|
|
|
nsMenuItemX* menuItem = static_cast<nsMenuItemX*>(mMenuObject);
|
2019-01-21 20:18:16 +03:00
|
|
|
if (menuItem->GetMenuItemType() != eRegularMenuItemType) return NS_ERROR_FAILURE;
|
2007-04-22 05:42:17 +04:00
|
|
|
}
|
|
|
|
|
2019-01-21 20:18:16 +03:00
|
|
|
if (!mContent) return NS_ERROR_FAILURE;
|
2007-04-22 05:42:17 +04:00
|
|
|
|
|
|
|
// First, look at the content node's "image" attribute.
|
|
|
|
nsAutoString imageURIString;
|
2017-12-07 21:13:50 +03:00
|
|
|
bool hasImageAttr =
|
2019-01-21 20:18:16 +03:00
|
|
|
mContent->IsElement() &&
|
|
|
|
mContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::image, imageURIString);
|
2007-04-22 05:42:17 +04:00
|
|
|
|
|
|
|
nsresult rv;
|
2018-03-22 21:20:41 +03:00
|
|
|
RefPtr<ComputedStyle> sc;
|
2018-01-11 11:17:57 +03:00
|
|
|
nsCOMPtr<nsIURI> iconURI;
|
2007-04-22 05:42:17 +04:00
|
|
|
if (!hasImageAttr) {
|
|
|
|
// If the content node has no "image" attribute, get the
|
|
|
|
// "list-style-image" property from CSS.
|
2019-01-02 16:05:23 +03:00
|
|
|
RefPtr<mozilla::dom::Document> document = mContent->GetComposedDoc();
|
2018-01-11 11:17:57 +03:00
|
|
|
if (!document || !mContent->IsElement()) {
|
2011-04-24 10:54:25 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
2018-01-11 11:17:57 +03:00
|
|
|
}
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2018-03-22 21:20:41 +03:00
|
|
|
sc = nsComputedDOMStyle::GetComputedStyle(mContent->AsElement(), nullptr);
|
2018-01-11 11:17:57 +03:00
|
|
|
if (!sc) {
|
2015-10-27 00:37:32 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
2018-01-11 11:17:57 +03:00
|
|
|
}
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2018-01-11 11:17:57 +03:00
|
|
|
iconURI = sc->StyleList()->GetListStyleImageURI();
|
|
|
|
if (!iconURI) {
|
2007-04-22 05:42:17 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
2018-01-11 11:17:57 +03:00
|
|
|
}
|
2016-12-14 23:52:57 +03:00
|
|
|
} else {
|
2017-09-21 03:09:00 +03:00
|
|
|
uint64_t dummy = 0;
|
2019-01-21 20:18:16 +03:00
|
|
|
nsContentUtils::GetContentPolicyTypeForUIImageLoading(
|
2019-09-06 22:03:15 +03:00
|
|
|
mContent, getter_AddRefs(mTriggeringPrincipal), mContentType, &dummy);
|
2018-01-11 11:17:57 +03:00
|
|
|
|
|
|
|
// If this menu item shouldn't have an icon, the string will be empty,
|
|
|
|
// and NS_NewURI will fail.
|
|
|
|
rv = NS_NewURI(getter_AddRefs(iconURI), imageURIString);
|
|
|
|
if (NS_FAILED(rv)) return rv;
|
2007-04-22 05:42:17 +04:00
|
|
|
}
|
|
|
|
|
2009-12-12 01:09:11 +03:00
|
|
|
// Empty the mImageRegionRect initially as the image region CSS could
|
|
|
|
// have been changed and now have an error or have been removed since the
|
|
|
|
// last GetIconURI call.
|
2011-04-19 07:07:23 +04:00
|
|
|
mImageRegionRect.SetEmpty();
|
2009-12-12 01:09:11 +03:00
|
|
|
|
2018-01-11 11:17:57 +03:00
|
|
|
iconURI.forget(aIconURI);
|
2009-12-12 01:09:11 +03:00
|
|
|
|
|
|
|
if (!hasImageAttr) {
|
|
|
|
// Check if the icon has a specified image region so that it can be
|
|
|
|
// cropped appropriately before being displayed.
|
2019-08-27 02:37:25 +03:00
|
|
|
const nsRect r = sc->StyleList()->GetImageRegion();
|
2009-12-12 01:09:11 +03:00
|
|
|
|
2018-01-11 11:17:57 +03:00
|
|
|
// Return NS_ERROR_FAILURE if the image region is invalid so the image
|
|
|
|
// is not drawn, and behavior is similar to XUL menus.
|
2018-01-12 08:39:49 +03:00
|
|
|
if (r.X() < 0 || r.Y() < 0 || r.Width() < 0 || r.Height() < 0) {
|
2018-01-11 11:17:57 +03:00
|
|
|
return NS_ERROR_FAILURE;
|
2009-12-12 01:09:11 +03:00
|
|
|
}
|
2018-01-11 11:17:57 +03:00
|
|
|
|
2018-01-12 08:39:49 +03:00
|
|
|
// 'auto' is represented by a [0, 0, 0, 0] rect. Only set mImageRegionRect
|
|
|
|
// if we have some other value.
|
|
|
|
if (!r.IsEmpty()) {
|
|
|
|
mImageRegionRect = r.ToNearestPixels(mozilla::AppUnitsPerCSSPixel());
|
|
|
|
}
|
2009-12-12 01:09:11 +03:00
|
|
|
}
|
|
|
|
|
2007-04-22 05:42:17 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2007-08-31 12:08:03 +04:00
|
|
|
//
|
2019-07-10 04:23:45 +03:00
|
|
|
// nsIconLoaderObserver
|
2007-08-31 12:08:03 +04:00
|
|
|
//
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2019-07-10 04:23:45 +03:00
|
|
|
nsresult nsMenuItemIconX::OnComplete(NSImage* aImage) {
|
2019-07-31 19:49:45 +03:00
|
|
|
if (!mNativeMenuItem) {
|
|
|
|
if (aImage) {
|
|
|
|
[aImage release];
|
|
|
|
}
|
Bug 753 - Remove nsIImage, gfxIImageFrame, and their implementations, and expose an equivalent api on imgIContainer. r=roc,josh,bz,longsonr,vlad,karlt,jimm,bsmedberg,mfinkle,peterw,peterv sr=vlad,roc
--HG--
rename : gfx/src/shared/gfxImageFrame.cpp => modules/libpr0n/src/imgFrame.cpp
rename : gfx/src/shared/gfxImageFrame.h => modules/libpr0n/src/imgFrame.h
2009-07-21 05:50:15 +04:00
|
|
|
return NS_ERROR_FAILURE;
|
2009-12-12 01:09:11 +03:00
|
|
|
}
|
2007-04-22 05:42:17 +04:00
|
|
|
|
2019-07-31 19:49:45 +03:00
|
|
|
if (!aImage) {
|
|
|
|
[mNativeMenuItem setImage:nil];
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2019-07-10 04:23:45 +03:00
|
|
|
[mNativeMenuItem setImage:aImage];
|
2019-07-20 01:08:41 +03:00
|
|
|
if (mMenuObject) {
|
|
|
|
mMenuObject->IconUpdated();
|
|
|
|
}
|
2019-07-10 04:23:45 +03:00
|
|
|
[aImage release];
|
2007-04-22 05:42:17 +04:00
|
|
|
return NS_OK;
|
|
|
|
}
|