зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1663784 - Add Windows platform support for IconLoader. r=mhowell
Depends on D89972 Differential Revision: https://phabricator.services.mozilla.com/D90007
This commit is contained in:
Родитель
5a0c26e13e
Коммит
455e99b3e0
|
@ -27,11 +27,16 @@ IconLoader::IconLoader(Helper* aHelper, nsINode* aContent,
|
|||
mLoadedIcon(false),
|
||||
mHelper(aHelper) {}
|
||||
|
||||
IconLoader::~IconLoader() {
|
||||
IconLoader::~IconLoader() { Destroy(); }
|
||||
|
||||
void IconLoader::Destroy() {
|
||||
if (mIconRequest) {
|
||||
mIconRequest->CancelAndForgetObserver(NS_BINDING_ABORTED);
|
||||
mIconRequest = nullptr;
|
||||
}
|
||||
if (mHelper) {
|
||||
mHelper = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
nsresult IconLoader::LoadIcon(nsIURI* aIconURI, bool aIsInternalIcon) {
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- 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 Windows.
|
||||
*/
|
||||
|
||||
#include "gfxPlatform.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "imgLoader.h"
|
||||
#include "imgRequestProxy.h"
|
||||
#include "mozilla/dom/Document.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIContent.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsToolkit.h"
|
||||
#include "nsWindowGfx.h"
|
||||
#include "IconLoaderHelperWin.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
using mozilla::gfx::SourceSurface;
|
||||
using mozilla::widget::IconLoader;
|
||||
using mozilla::widget::IconLoaderListenerWin;
|
||||
|
||||
namespace mozilla::widget {
|
||||
|
||||
IconLoaderHelperWin::IconLoaderHelperWin(IconLoaderListenerWin* aListener)
|
||||
: mLoadListener(aListener) {
|
||||
MOZ_ASSERT(aListener);
|
||||
}
|
||||
|
||||
IconLoaderHelperWin::~IconLoaderHelperWin() { Destroy(); }
|
||||
|
||||
nsresult IconLoaderHelperWin::OnComplete(imgIContainer* aImage,
|
||||
const nsIntRect& aRect) {
|
||||
NS_ENSURE_ARG_POINTER(aImage);
|
||||
|
||||
nsresult rv = nsWindowGfx::CreateIcon(
|
||||
aImage, false, LayoutDeviceIntPoint(),
|
||||
nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon),
|
||||
&mNativeIconImage);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mLoadListener->OnComplete();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
HICON IconLoaderHelperWin::GetNativeIconImage() {
|
||||
if (mNativeIconImage) {
|
||||
return mNativeIconImage;
|
||||
}
|
||||
return ::LoadIcon(::GetModuleHandle(NULL), IDI_APPLICATION);
|
||||
}
|
||||
|
||||
void IconLoaderHelperWin::Destroy() {
|
||||
if (mNativeIconImage) {
|
||||
::DestroyIcon(mNativeIconImage);
|
||||
mNativeIconImage = nullptr;
|
||||
}
|
||||
if (mLoadListener) {
|
||||
mLoadListener = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla::widget
|
|
@ -0,0 +1,63 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_widget_IconLoaderHelperWin_h
|
||||
#define mozilla_widget_IconLoaderHelperWin_h
|
||||
|
||||
#include "mozilla/widget/IconLoader.h"
|
||||
|
||||
namespace mozilla::widget {
|
||||
|
||||
/**
|
||||
* Classes that want to hear about when icons load should subclass
|
||||
* IconLoaderListenerWin, and implement the OnComplete() method,
|
||||
* which will be called once the load of the icon has completed.
|
||||
*/
|
||||
class IconLoaderListenerWin {
|
||||
public:
|
||||
IconLoaderListenerWin() = default;
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(mozilla::widget::IconLoaderListenerWin)
|
||||
|
||||
virtual nsresult OnComplete() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~IconLoaderListenerWin() = default;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a Helper used with mozilla::widget::IconLoader that implements the
|
||||
* Windows-specific functionality for converting a loaded icon into an HICON.
|
||||
*/
|
||||
class IconLoaderHelperWin final : public mozilla::widget::IconLoader::Helper {
|
||||
public:
|
||||
explicit IconLoaderHelperWin(
|
||||
mozilla::widget::IconLoaderListenerWin* aLoadListener);
|
||||
|
||||
nsresult OnComplete(imgIContainer* aImage, const nsIntRect& aRect) override;
|
||||
|
||||
/**
|
||||
* IconLoaderHelperWin will default the HICON returned by GetNativeIconImage
|
||||
* to the application icon. Once the load of the icon by IconLoader has
|
||||
* completed, GetNativeIconImage will return the loaded icon.
|
||||
*
|
||||
* Note that IconLoaderHelperWin owns this HICON. If you don't need it to hold
|
||||
* onto the HICON anymore, call Destroy on it to deallocate. The
|
||||
* IconLoaderHelperWin destructor will also deallocate the HICON if necessary.
|
||||
*/
|
||||
HICON GetNativeIconImage();
|
||||
void Destroy();
|
||||
|
||||
protected:
|
||||
~IconLoaderHelperWin();
|
||||
|
||||
private:
|
||||
RefPtr<mozilla::widget::IconLoaderListenerWin> mLoadListener;
|
||||
HICON mNativeIconImage;
|
||||
};
|
||||
|
||||
} // namespace mozilla::widget
|
||||
|
||||
#endif // mozilla_widget_IconLoaderHelperWin_h
|
|
@ -11,26 +11,32 @@
|
|||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsIContentPolicy.h"
|
||||
#include "nsMenuFrame.h"
|
||||
#include "nsMenuPopupFrame.h"
|
||||
#include "nsXULPopupManager.h"
|
||||
#include "IconLoaderHelperWin.h"
|
||||
|
||||
namespace mozilla::widget {
|
||||
|
||||
using mozilla::LinkedListElement;
|
||||
using mozilla::dom::Element;
|
||||
|
||||
class StatusBarEntry final : public LinkedListElement<RefPtr<StatusBarEntry>> {
|
||||
class StatusBarEntry final : public LinkedListElement<RefPtr<StatusBarEntry>>,
|
||||
public mozilla::widget::IconLoaderListenerWin {
|
||||
public:
|
||||
explicit StatusBarEntry(Element* aMenu);
|
||||
nsresult Init();
|
||||
LRESULT OnMessage(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp);
|
||||
const Element* GetMenu() { return mMenu; };
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(StatusBarEntry)
|
||||
nsresult OnComplete();
|
||||
|
||||
private:
|
||||
~StatusBarEntry();
|
||||
RefPtr<mozilla::widget::IconLoader> mIconLoader;
|
||||
RefPtr<mozilla::widget::IconLoaderHelperWin> mIconLoaderHelper;
|
||||
RefPtr<Element> mMenu;
|
||||
NOTIFYICONDATAW mIconData;
|
||||
boolean mInitted;
|
||||
|
@ -50,6 +56,7 @@ StatusBarEntry::StatusBarEntry(Element* aMenu) : mMenu(aMenu), mInitted(false) {
|
|||
/* uVersion */ {NOTIFYICON_VERSION},
|
||||
/* szInfoTitle */ L"",
|
||||
/* dwInfoFlags */ 0};
|
||||
MOZ_ASSERT(mMenu);
|
||||
}
|
||||
|
||||
StatusBarEntry::~StatusBarEntry() {
|
||||
|
@ -61,6 +68,57 @@ StatusBarEntry::~StatusBarEntry() {
|
|||
}
|
||||
|
||||
nsresult StatusBarEntry::Init() {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// First, look at the content node's "image" attribute.
|
||||
nsAutoString imageURIString;
|
||||
bool hasImageAttr =
|
||||
mMenu->GetAttr(kNameSpaceID_None, nsGkAtoms::image, imageURIString);
|
||||
|
||||
nsresult rv;
|
||||
RefPtr<ComputedStyle> sc;
|
||||
nsCOMPtr<nsIURI> iconURI;
|
||||
if (!hasImageAttr) {
|
||||
// If the content node has no "image" attribute, get the
|
||||
// "list-style-image" property from CSS.
|
||||
RefPtr<mozilla::dom::Document> document = mMenu->GetComposedDoc();
|
||||
if (!document) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
sc = nsComputedDOMStyle::GetComputedStyle(mMenu, nullptr);
|
||||
if (!sc) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
iconURI = sc->StyleList()->GetListStyleImageURI();
|
||||
} else {
|
||||
uint64_t dummy = 0;
|
||||
nsContentPolicyType policyType;
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal = mMenu->NodePrincipal();
|
||||
nsContentUtils::GetContentPolicyTypeForUIImageLoading(
|
||||
mMenu, getter_AddRefs(triggeringPrincipal), policyType, &dummy);
|
||||
if (policyType != nsIContentPolicy::TYPE_INTERNAL_IMAGE) {
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
mIconLoaderHelper = new IconLoaderHelperWin(this);
|
||||
nsIntRect rect;
|
||||
mIconLoader = new IconLoader(mIconLoaderHelper, mMenu, rect);
|
||||
if (!mIconLoader || !mIconLoaderHelper) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
if (iconURI) {
|
||||
rv = mIconLoader->LoadIcon(iconURI);
|
||||
}
|
||||
|
||||
HWND iconWindow;
|
||||
NS_ENSURE_TRUE(iconWindow = ::CreateWindowExW(
|
||||
/* extended style */ 0,
|
||||
|
@ -76,7 +134,7 @@ nsresult StatusBarEntry::Init() {
|
|||
::SetWindowLongPtr(iconWindow, GWLP_USERDATA, (LONG_PTR)this);
|
||||
|
||||
mIconData.hWnd = iconWindow;
|
||||
mIconData.hIcon = ::LoadIcon(::GetModuleHandle(NULL), IDI_APPLICATION);
|
||||
mIconData.hIcon = mIconLoaderHelper->GetNativeIconImage();
|
||||
|
||||
nsAutoString labelAttr;
|
||||
mMenu->GetAttr(kNameSpaceID_None, nsGkAtoms::label, labelAttr);
|
||||
|
@ -93,6 +151,23 @@ nsresult StatusBarEntry::Init() {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult StatusBarEntry::OnComplete() {
|
||||
RefPtr<StatusBarEntry> kungFuDeathGrip = this;
|
||||
mIconData.hIcon = mIconLoaderHelper->GetNativeIconImage();
|
||||
|
||||
::Shell_NotifyIconW(NIM_MODIFY, &mIconData);
|
||||
|
||||
// To simplify things, we won't react to CSS changes to update the icon
|
||||
// with this implementation. We can get rid of the IconLoader and Helper
|
||||
// at this point, which will also free the allocated HICON.
|
||||
mIconLoaderHelper->Destroy();
|
||||
mIconLoader->ReleaseJSObjects();
|
||||
mIconLoader->Destroy();
|
||||
mIconLoader = nullptr;
|
||||
mIconLoaderHelper = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
LRESULT StatusBarEntry::OnMessage(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp) {
|
||||
if (msg == WM_USER && (lp == WM_LBUTTONUP || lp == WM_RBUTTONUP)) {
|
||||
nsMenuFrame* menu = do_QueryFrame(mMenu->GetPrimaryFrame());
|
||||
|
|
|
@ -48,6 +48,7 @@ UNIFIED_SOURCES += [
|
|||
'AudioSession.cpp',
|
||||
'CompositorWidgetChild.cpp',
|
||||
'GfxInfo.cpp',
|
||||
'IconLoaderHelperWin.cpp',
|
||||
'IEnumFE.cpp',
|
||||
'IMMHandler.cpp',
|
||||
'InkCollector.cpp',
|
||||
|
@ -155,6 +156,7 @@ if CONFIG['MOZ_ENABLE_SKIA_PDF']:
|
|||
LOCAL_INCLUDES += [
|
||||
'/layout/forms',
|
||||
'/layout/generic',
|
||||
'/layout/style',
|
||||
'/layout/xul',
|
||||
'/toolkit/xre',
|
||||
'/widget',
|
||||
|
|
Загрузка…
Ссылка в новой задаче