summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/nsMenuItemIconX.mm
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/cocoa/nsMenuItemIconX.mm173
1 files changed, 173 insertions, 0 deletions
diff --git a/widget/cocoa/nsMenuItemIconX.mm b/widget/cocoa/nsMenuItemIconX.mm
new file mode 100644
index 0000000000..6749d787de
--- /dev/null
+++ b/widget/cocoa/nsMenuItemIconX.mm
@@ -0,0 +1,173 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 in native menu items on Mac OS X.
+ */
+
+/* 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.
+
+ We use <limits> to get the libstdc++ version. */
+#include <limits>
+#if __GLIBCXX__ <= 20070719
+# ifndef __EXCEPTIONS
+# define __EXCEPTIONS
+# endif
+#endif
+
+#include "MOZIconHelper.h"
+#include "mozilla/dom/Document.h"
+#include "mozilla/dom/DocumentInlines.h"
+#include "nsCocoaUtils.h"
+#include "nsComputedDOMStyle.h"
+#include "nsContentUtils.h"
+#include "nsGkAtoms.h"
+#include "nsIContent.h"
+#include "nsIContentPolicy.h"
+#include "nsMenuItemX.h"
+#include "nsMenuItemIconX.h"
+#include "nsNameSpaceManager.h"
+#include "nsObjCExceptions.h"
+
+using namespace mozilla;
+
+using mozilla::dom::Element;
+using mozilla::widget::IconLoader;
+
+static const uint32_t kIconSize = 16;
+
+nsMenuItemIconX::nsMenuItemIconX(Listener* aListener) : mListener(aListener) {
+ MOZ_COUNT_CTOR(nsMenuItemIconX);
+}
+
+nsMenuItemIconX::~nsMenuItemIconX() {
+ if (mIconLoader) {
+ mIconLoader->Destroy();
+ }
+ if (mIconImage) {
+ [mIconImage release];
+ mIconImage = nil;
+ }
+ MOZ_COUNT_DTOR(nsMenuItemIconX);
+}
+
+void nsMenuItemIconX::SetupIcon(nsIContent* aContent) {
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+ bool shouldHaveIcon = StartIconLoad(aContent);
+ if (!shouldHaveIcon) {
+ // 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.
+ if (mIconImage) {
+ [mIconImage release];
+ mIconImage = nil;
+ }
+ return;
+ }
+
+ if (!mIconImage) {
+ // Set a placeholder icon, so that the menuitem reserves space for the icon
+ // during the load and there is no sudden shift once the icon finishes
+ // loading.
+ NSSize iconSize = NSMakeSize(kIconSize, kIconSize);
+ mIconImage = [[MOZIconHelper placeholderIconWithSize:iconSize] retain];
+ }
+
+ NS_OBJC_END_TRY_ABORT_BLOCK;
+}
+
+bool nsMenuItemIconX::StartIconLoad(nsIContent* aContent) {
+ RefPtr<nsIURI> iconURI = GetIconURI(aContent);
+ if (!iconURI) {
+ return false;
+ }
+
+ if (!mIconLoader) {
+ mIconLoader = new IconLoader(this);
+ }
+
+ nsresult rv = mIconLoader->LoadIcon(iconURI, aContent);
+ return NS_SUCCEEDED(rv);
+}
+
+already_AddRefed<nsIURI> nsMenuItemIconX::GetIconURI(nsIContent* aContent) {
+ // First, look at the content node's "image" attribute.
+ nsAutoString imageURIString;
+ bool hasImageAttr =
+ aContent->IsElement() &&
+ aContent->AsElement()->GetAttr(nsGkAtoms::image, imageURIString);
+
+ if (hasImageAttr) {
+ // Use the URL from the image attribute.
+ // If this menu item shouldn't have an icon, the string will be empty,
+ // and NS_NewURI will fail.
+ RefPtr<nsIURI> iconURI;
+ nsresult rv = NS_NewURI(getter_AddRefs(iconURI), imageURIString);
+ if (NS_FAILED(rv)) {
+ return nullptr;
+ }
+ return iconURI.forget();
+ }
+
+ // If the content node has no "image" attribute, get the
+ // "list-style-image" property from CSS.
+ RefPtr<mozilla::dom::Document> document = aContent->GetComposedDoc();
+ if (!document || !aContent->IsElement()) {
+ return nullptr;
+ }
+
+ RefPtr<const ComputedStyle> sc =
+ nsComputedDOMStyle::GetComputedStyle(aContent->AsElement());
+ if (!sc) {
+ return nullptr;
+ }
+
+ RefPtr<nsIURI> iconURI = sc->StyleList()->GetListStyleImageURI();
+ if (!iconURI) {
+ return nullptr;
+ }
+
+ mComputedStyle = std::move(sc);
+ mPresContext = document->GetPresContext();
+
+ return iconURI.forget();
+}
+
+//
+// mozilla::widget::IconLoader::Listener
+//
+
+nsresult nsMenuItemIconX::OnComplete(imgIContainer* aImage) {
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
+
+ if (mIconImage) {
+ [mIconImage release];
+ mIconImage = nil;
+ }
+ RefPtr<nsPresContext> pc = mPresContext.get();
+ mIconImage = [[MOZIconHelper
+ iconImageFromImageContainer:aImage
+ withSize:NSMakeSize(kIconSize, kIconSize)
+ presContext:pc
+ computedStyle:mComputedStyle
+ scaleFactor:0.0f] retain];
+ mComputedStyle = nullptr;
+ mPresContext = nullptr;
+
+ if (mListener) {
+ mListener->IconUpdated();
+ }
+
+ mIconLoader->Destroy();
+
+ return NS_OK;
+
+ NS_OBJC_END_TRY_ABORT_BLOCK;
+}