summaryrefslogtreecommitdiffstats
path: root/widget/cocoa/IconLoaderHelperCocoa.mm
diff options
context:
space:
mode:
Diffstat (limited to 'widget/cocoa/IconLoaderHelperCocoa.mm')
-rw-r--r--widget/cocoa/IconLoaderHelperCocoa.mm141
1 files changed, 141 insertions, 0 deletions
diff --git a/widget/cocoa/IconLoaderHelperCocoa.mm b/widget/cocoa/IconLoaderHelperCocoa.mm
new file mode 100644
index 0000000000..0d379b8e9f
--- /dev/null
+++ b/widget/cocoa/IconLoaderHelperCocoa.mm
@@ -0,0 +1,141 @@
+/* -*- 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 "gfxPlatform.h"
+#include "imgIContainer.h"
+#include "imgLoader.h"
+#include "imgRequestProxy.h"
+#include "mozilla/dom/Document.h"
+#include "nsCocoaUtils.h"
+#include "nsContentUtils.h"
+#include "nsIContent.h"
+#include "nsNameSpaceManager.h"
+#include "nsNetUtil.h"
+#include "nsObjCExceptions.h"
+#include "nsThreadUtils.h"
+#include "nsToolkit.h"
+#include "IconLoaderHelperCocoa.h"
+
+using namespace mozilla;
+
+using mozilla::gfx::SourceSurface;
+using mozilla::widget::IconLoaderListenerCocoa;
+
+namespace mozilla::widget {
+
+NS_IMPL_ISUPPORTS0(IconLoaderHelperCocoa)
+
+IconLoaderHelperCocoa::IconLoaderHelperCocoa(IconLoaderListenerCocoa* aListener,
+ uint32_t aIconHeight, uint32_t aIconWidth,
+ CGFloat aScaleFactor)
+ : mLoadListener(aListener),
+ mIconHeight(aIconHeight),
+ mIconWidth(aIconWidth),
+ mScaleFactor(aScaleFactor) {
+ // Placeholder icon, which will later be replaced.
+ mNativeIconImage = [[NSImage alloc] initWithSize:NSMakeSize(mIconHeight, mIconWidth)];
+ MOZ_ASSERT(aListener);
+}
+
+IconLoaderHelperCocoa::~IconLoaderHelperCocoa() { Destroy(); }
+
+nsresult IconLoaderHelperCocoa::OnComplete(imgIContainer* aImage, const nsIntRect& aRect) {
+ NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT
+
+ NS_ENSURE_ARG_POINTER(aImage);
+
+ bool isEntirelyBlack = false;
+ NSImage* newImage = nil;
+ nsresult rv;
+ if (mScaleFactor != 0.0f) {
+ rv = nsCocoaUtils::CreateNSImageFromImageContainer(aImage, imgIContainer::FRAME_CURRENT,
+ &newImage, mScaleFactor, &isEntirelyBlack);
+ } else {
+ rv = nsCocoaUtils::CreateDualRepresentationNSImageFromImageContainer(
+ aImage, imgIContainer::FRAME_CURRENT, &newImage, &isEntirelyBlack);
+ }
+
+ if (NS_FAILED(rv) || !newImage) {
+ mNativeIconImage = nil;
+ [newImage release];
+ return NS_ERROR_FAILURE;
+ }
+
+ NSSize requestedSize = NSMakeSize(mIconWidth, mIconHeight);
+
+ int32_t origWidth = 0, origHeight = 0;
+ aImage->GetWidth(&origWidth);
+ aImage->GetHeight(&origHeight);
+
+ bool createSubImage =
+ !(aRect.x == 0 && aRect.y == 0 && aRect.width == origWidth && aRect.height == origHeight);
+
+ if (createSubImage) {
+ // If aRect is set using CSS, we need to slice a piece out of the
+ // overall image to use as the icon.
+ NSImage* subImage =
+ [NSImage imageWithSize:requestedSize
+ flipped:NO
+ drawingHandler:^BOOL(NSRect subImageRect) {
+ [newImage drawInRect:NSMakeRect(0, 0, mIconWidth, mIconHeight)
+ fromRect:NSMakeRect(aRect.x, aRect.y, aRect.width, aRect.height)
+ operation:NSCompositingOperationCopy
+ 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
+ // template. This will cause macOS to use the image's alpha channel as a mask
+ // and it will fill it with a color that looks good in the context that it's
+ // used in. For example, for regular menu items, the image will be black, but
+ // when the menu item is hovered (and its background is blue), it will be
+ // filled with white.
+ [newImage setTemplate:isEntirelyBlack];
+
+ [newImage setSize:requestedSize];
+
+ NSImage* placeholderImage = mNativeIconImage;
+ mNativeIconImage = newImage;
+ [placeholderImage release];
+ placeholderImage = nil;
+
+ mLoadListener->OnComplete();
+
+ return NS_OK;
+ NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT
+}
+
+NSImage* IconLoaderHelperCocoa::GetNativeIconImage() { return mNativeIconImage; }
+
+void IconLoaderHelperCocoa::Destroy() {
+ if (mNativeIconImage) {
+ [mNativeIconImage release];
+ mNativeIconImage = nil;
+ }
+}
+
+} // namespace mozilla::widget