Bug 515907 - Support taskbar icon overlays in Windows 7. Original patch by Tim Miller <mille449@gmail.com>. r=jimm, sr=roc
authorSiddharth Agarwal <sid.bugzilla@gmail.com>
Thu, 29 Sep 2011 00:06:43 +0530
changeset 77762 9cd3dc884d1c296656e5b07192e7c3143a5250c7
parent 77761 f3022823eb876895edb22eb8aaca29fa3787ad42
child 77763 b045aa0216fb37e1ba9a90114ac6615ccd20a180
push id2237
push usersid.bugzilla@gmail.com
push dateWed, 28 Sep 2011 18:42:05 +0000
treeherdermozilla-inbound@9cd3dc884d1c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjimm, roc
bugs515907
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 515907 - Support taskbar icon overlays in Windows 7. Original patch by Tim Miller <mille449@gmail.com>. r=jimm, sr=roc
widget/public/Makefile.in
widget/public/nsITaskbarOverlayIconController.idl
widget/public/nsIWinTaskbar.idl
widget/src/windows/TaskbarPreviewButton.cpp
widget/src/windows/TaskbarTabPreview.cpp
widget/src/windows/TaskbarWindowPreview.cpp
widget/src/windows/TaskbarWindowPreview.h
widget/src/windows/WinTaskbar.cpp
widget/src/windows/nsWindow.cpp
widget/src/windows/nsWindowGfx.cpp
widget/src/windows/nsWindowGfx.h
--- a/widget/public/Makefile.in
+++ b/widget/public/Makefile.in
@@ -135,16 +135,17 @@ XPIDLSRCS	+= nsIPrintSettingsWin.idl \
 		nsIWinTaskbar.idl	\
 		nsITaskbarPreview.idl	\
 		nsITaskbarTabPreview.idl \
 		nsITaskbarWindowPreview.idl \
 		nsITaskbarPreviewController.idl \
 		nsITaskbarPreviewButton.idl \
 		nsITaskbarProgress.idl \
 		nsITaskbarPreviewButton.idl \
+		nsITaskbarOverlayIconController.idl \
 		nsIJumpListBuilder.idl \
 		nsIJumpListItem.idl \
 		$(NULL)
 endif
 
 ifeq ($(MOZ_WIDGET_TOOLKIT),cocoa)
 XPIDLSRCS +=	nsIMacDockSupport.idl \
 		nsIStandaloneNativeMenu.idl \
new file mode 100644
--- /dev/null
+++ b/widget/public/nsITaskbarOverlayIconController.idl
@@ -0,0 +1,72 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Tim Miller <mille449@gmail.com>.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Siddharth Agarwal <sid.bugzilla@gmail.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface imgIContainer;
+
+/**
+ * Starting in Windows 7, applications can display an overlay on the icon in
+ * the taskbar. This class wraps around the native functionality to do this.
+ */
+[scriptable, uuid(b1858889-a698-428a-a14b-b5d60cff6de2)]
+interface nsITaskbarOverlayIconController : nsISupports
+{
+  /**
+   * Sets the overlay icon and its corresponding alt text.
+   *
+   * @param statusIcon The handle to the overlay icon. The icon will be scaled
+   *                   to the small icon size (16x16 at 96 dpi). Can be null, in
+   *                   which case if the taskbar button represents a single window
+   *                   the icon is removed.
+   * @param statusDescription The alt text version of the information
+   *                          conveyed by the overlay, for accessibility
+   *                          purposes.
+   *
+   * @note The behavior for window groups is managed by Windows.
+   * - If an overlay icon is set for any window in a window group and another
+   *   overlay icon is already applied to the corresponding taskbar button, that
+   *   existing overlay is replaced.
+   * - If null is passed in to replace the overlay currently being displayed,
+   *   and if a previous overlay set for a different window in the group is
+   *   still available, then that previous overlay is displayed.
+   */
+  void setOverlayIcon(in imgIContainer statusIcon,
+                      in AString statusDescription);
+};
--- a/widget/public/nsIWinTaskbar.idl
+++ b/widget/public/nsIWinTaskbar.idl
@@ -43,16 +43,17 @@
 #include "nsISupports.idl"
 #include "nsIBaseWindow.idl"
 
 interface nsIDocShell;
 interface nsITaskbarTabPreview;
 interface nsITaskbarWindowPreview;
 interface nsITaskbarPreviewController;
 interface nsITaskbarProgress;
+interface nsITaskbarOverlayIconController;
 interface nsIJumpListBuilder;
 interface nsIDOMWindow;
 
 /*
  * nsIWinTaskbar
  *
  * This interface represents a service which exposes the APIs provided by the
  * Windows taskbar to applications.
@@ -78,17 +79,17 @@ interface nsIDOMWindow;
  * When taskbar icons are combined as is the default in Windows 7, the progress
  * for those windows is also combined as defined here:
  * http://msdn.microsoft.com/en-us/library/dd391697%28VS.85%29.aspx
  *
  * Applications may also define custom taskbar jump lists on application shortcuts.
  * See nsIJumpListBuilder for more information.
  */
 
-[scriptable, uuid(9fc572db-1089-4d43-9121-f4833d77a2df)]
+[scriptable, uuid(3232f40a-e94b-432d-9496-096abf1387bd)]
 interface nsIWinTaskbar : nsISupports
 {
   /**
    * Returns true if the operating system supports Win7+ taskbar features.
    * This property acts as a replacement for in-place os version checking.
    */
   readonly attribute boolean available;
 
@@ -128,16 +129,27 @@ interface nsIWinTaskbar : nsISupports
   /**
    * Gets the taskbar progress for a window. The docshell is used to find the
    * toplevel window. See the documentation for nsITaskbarProgress for more
    * information.
    */
   nsITaskbarProgress getTaskbarProgress(in nsIDocShell shell);
 
   /**
+   * Taskbar icon overlay
+   */
+
+  /**
+   * Gets the taskbar icon overlay controller for a window. The docshell is used
+   * to find the toplevel window. See the documentation in
+   * nsITaskbarOverlayIconController for more details.
+   */
+  nsITaskbarOverlayIconController getOverlayIconController(in nsIDocShell shell);
+
+  /**
    * Taskbar and start menu jump list management
    */
 
   /**
    * Retrieve a taskbar jump list builder
    *
    * Fails if a jump list build operation has already been initiated, developers
    * should make use of a single instance of nsIJumpListBuilder for building lists
--- a/widget/src/windows/TaskbarPreviewButton.cpp
+++ b/widget/src/windows/TaskbarPreviewButton.cpp
@@ -135,17 +135,19 @@ TaskbarPreviewButton::GetImage(imgIConta
 }
 
 NS_IMETHODIMP
 TaskbarPreviewButton::SetImage(imgIContainer *img) {
   if (Button().hIcon)
     ::DestroyIcon(Button().hIcon);
   if (img) {
     nsresult rv;
-    rv = nsWindowGfx::CreateIcon(img, PR_FALSE, 0, 0, &Button().hIcon);
+    rv = nsWindowGfx::CreateIcon(img, PR_FALSE, 0, 0,
+                                 nsWindowGfx::GetIconMetrics(nsWindowGfx::kRegularIcon),
+                                 &Button().hIcon);
     NS_ENSURE_SUCCESS(rv, rv);
   } else {
     Button().hIcon = NULL;
   }
   return Update();
 }
 
 NS_IMETHODIMP
--- a/widget/src/windows/TaskbarTabPreview.cpp
+++ b/widget/src/windows/TaskbarTabPreview.cpp
@@ -120,17 +120,19 @@ TaskbarTabPreview::SetTitle(const nsAStr
   return mVisible ? UpdateTitle() : NS_OK;
 }
 
 NS_IMETHODIMP
 TaskbarTabPreview::SetIcon(imgIContainer *icon) {
   HICON hIcon = NULL;
   if (icon) {
     nsresult rv;
-    rv = nsWindowGfx::CreateIcon(icon, PR_FALSE, 0, 0, &hIcon);
+    rv = nsWindowGfx::CreateIcon(icon, PR_FALSE, 0, 0,
+                                 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
+                                 &hIcon);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (mIcon)
     ::DestroyIcon(mIcon);
   mIcon = hIcon;
   mIconImage = icon;
   return mVisible ? UpdateIcon() : NS_OK;
--- a/widget/src/windows/TaskbarWindowPreview.cpp
+++ b/widget/src/windows/TaskbarWindowPreview.cpp
@@ -42,31 +42,33 @@
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
 
 #include <nsITaskbarPreviewController.h>
 #include "TaskbarWindowPreview.h"
 #include "WindowHook.h"
 #include "nsUXThemeData.h"
 #include "TaskbarPreviewButton.h"
 #include "nsWindow.h"
+#include "nsWindowGfx.h"
 
 namespace mozilla {
 namespace widget {
 
 namespace {
 PRBool WindowHookProc(void *aContext, HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam, LRESULT *aResult)
 {
   TaskbarWindowPreview *preview = reinterpret_cast<TaskbarWindowPreview*>(aContext);
   *aResult = preview->WndProc(nMsg, wParam, lParam);
   return PR_TRUE;
 }
 }
 
-NS_IMPL_ISUPPORTS3(TaskbarWindowPreview, nsITaskbarWindowPreview,
-                   nsITaskbarProgress, nsISupportsWeakReference)
+NS_IMPL_ISUPPORTS4(TaskbarWindowPreview, nsITaskbarWindowPreview,
+                   nsITaskbarProgress, nsITaskbarOverlayIconController,
+                   nsISupportsWeakReference)
 
 /**
  * These correspond directly to the states defined in nsITaskbarProgress.idl, so
  * they should be kept in sync.
  */
 static TBPFLAG sNativeStates[] =
 {
   TBPF_NOPROGRESS,
@@ -77,35 +79,41 @@ static TBPFLAG sNativeStates[] =
 };
 
 TaskbarWindowPreview::TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell)
   : TaskbarPreview(aTaskbar, aController, aHWND, aShell),
     mCustomDrawing(PR_FALSE),
     mHaveButtons(PR_FALSE),
     mState(TBPF_NOPROGRESS),
     mCurrentValue(0),
-    mMaxValue(0)
+    mMaxValue(0),
+    mOverlayIcon(NULL)
 {
   // Window previews are visible by default
   (void) SetVisible(PR_TRUE);
 
   memset(mThumbButtons, 0, sizeof mThumbButtons);
   for (PRInt32 i = 0; i < nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS; i++) {
     mThumbButtons[i].dwMask = THB_FLAGS | THB_ICON | THB_TOOLTIP;
     mThumbButtons[i].iId = i;
     mThumbButtons[i].dwFlags = THBF_HIDDEN;
   }
 
   WindowHook &hook = GetWindowHook();
   if (!CanMakeTaskbarCalls())
     hook.AddMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
-                    TaskbarProgressWindowHook, this);
+                    TaskbarWindowHook, this);
 }
 
 TaskbarWindowPreview::~TaskbarWindowPreview() {
+  if (mOverlayIcon) {
+    ::DestroyIcon(mOverlayIcon);
+    mOverlayIcon = NULL;
+  }
+
   if (IsWindowAvailable()) {
     DetachFromNSWindow();
   } else {
     mWnd = NULL;
   }
 }
 
 nsresult
@@ -194,37 +202,75 @@ TaskbarWindowPreview::SetProgressState(n
   mState = nativeState;
   mCurrentValue = aCurrentValue;
   mMaxValue = aMaxValue;
 
   // Only update if we can
   return CanMakeTaskbarCalls() ? UpdateTaskbarProgress() : NS_OK;
 }
 
+NS_IMETHODIMP
+TaskbarWindowPreview::SetOverlayIcon(imgIContainer* aStatusIcon,
+                                     const nsAString& aStatusDescription) {
+  nsresult rv;
+  if (aStatusIcon) {
+    // The image shouldn't be animated
+    PRBool isAnimated;
+    rv = aStatusIcon->GetAnimated(&isAnimated);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_FALSE(isAnimated, NS_ERROR_INVALID_ARG);
+  }
+
+  HICON hIcon = NULL;
+  if (aStatusIcon) {
+    rv = nsWindowGfx::CreateIcon(aStatusIcon, false, 0, 0,
+                                 nsWindowGfx::GetIconMetrics(nsWindowGfx::kSmallIcon),
+                                 &hIcon);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (mOverlayIcon)
+    ::DestroyIcon(mOverlayIcon);
+  mOverlayIcon = hIcon;
+  mIconDescription = aStatusDescription;
+
+  // Only update if we can
+  return CanMakeTaskbarCalls() ? UpdateOverlayIcon() : NS_OK;
+}
+
 nsresult
 TaskbarWindowPreview::UpdateTaskbarProperties() {
   if (mHaveButtons) {
     if (FAILED(mTaskbar->ThumbBarAddButtons(mWnd, nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS, mThumbButtons)))
       return NS_ERROR_FAILURE;
   }
   nsresult rv = UpdateTaskbarProgress();
   NS_ENSURE_SUCCESS(rv, rv);
+  rv = UpdateOverlayIcon();
+  NS_ENSURE_SUCCESS(rv, rv);
   return TaskbarPreview::UpdateTaskbarProperties();
 }
 
 nsresult
 TaskbarWindowPreview::UpdateTaskbarProgress() {
   HRESULT hr = mTaskbar->SetProgressState(mWnd, mState);
   if (SUCCEEDED(hr) && mState != TBPF_NOPROGRESS &&
       mState != TBPF_INDETERMINATE)
     hr = mTaskbar->SetProgressValue(mWnd, mCurrentValue, mMaxValue);
 
   return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
 }
 
+nsresult
+TaskbarWindowPreview::UpdateOverlayIcon() {
+  HRESULT hr = mTaskbar->SetOverlayIcon(mWnd, mOverlayIcon,
+                                        mIconDescription.get());
+  return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
+}
+
 LRESULT
 TaskbarWindowPreview::WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam) {
   nsRefPtr<TaskbarWindowPreview> kungFuDeathGrip(this);
   switch (nMsg) {
     case WM_COMMAND:
       {
         PRUint32 id = LOWORD(wParam);
         PRUint32 index = id;
@@ -235,27 +281,27 @@ TaskbarWindowPreview::WndProc(UINT nMsg,
       }
       return 0;
   }
   return TaskbarPreview::WndProc(nMsg, wParam, lParam);
 }
 
 /* static */
 PRBool
-TaskbarWindowPreview::TaskbarProgressWindowHook(void *aContext,
-                                                HWND hWnd, UINT nMsg,
-                                                WPARAM wParam, LPARAM lParam,
-                                                LRESULT *aResult)
+TaskbarWindowPreview::TaskbarWindowHook(void *aContext,
+                                        HWND hWnd, UINT nMsg,
+                                        WPARAM wParam, LPARAM lParam,
+                                        LRESULT *aResult)
 {
   NS_ASSERTION(nMsg == nsAppShell::GetTaskbarButtonCreatedMessage(),
                "Window hook proc called with wrong message");
   TaskbarWindowPreview *preview =
     reinterpret_cast<TaskbarWindowPreview*>(aContext);
   // Now we can make all the calls to mTaskbar
-  preview->UpdateTaskbarProgress();
+  preview->UpdateTaskbarProperties();
   return PR_FALSE;
 }
 
 nsresult
 TaskbarWindowPreview::Enable() {
   nsresult rv = TaskbarPreview::Enable();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -277,17 +323,17 @@ TaskbarWindowPreview::Disable() {
 void
 TaskbarWindowPreview::DetachFromNSWindow() {
   // Remove the hooks we have for drawing
   SetEnableCustomDrawing(PR_FALSE);
 
   WindowHook &hook = GetWindowHook();
   (void) hook.RemoveHook(WM_COMMAND, WindowHookProc, this);
   (void) hook.RemoveMonitor(nsAppShell::GetTaskbarButtonCreatedMessage(),
-                            TaskbarProgressWindowHook, this);
+                            TaskbarWindowHook, this);
 
   TaskbarPreview::DetachFromNSWindow();
 }
 
 nsresult
 TaskbarWindowPreview::UpdateButtons() {
   NS_ASSERTION(mVisible, "UpdateButtons called on invisible preview");
 
--- a/widget/src/windows/TaskbarWindowPreview.h
+++ b/widget/src/windows/TaskbarWindowPreview.h
@@ -41,35 +41,38 @@
 
 #ifndef __mozilla_widget_TaskbarWindowPreview_h__
 #define __mozilla_widget_TaskbarWindowPreview_h__
 
 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
 
 #include "nsITaskbarWindowPreview.h"
 #include "nsITaskbarProgress.h"
+#include "nsITaskbarOverlayIconController.h"
 #include "TaskbarPreview.h"
 #include <nsWeakReference.h>
 
 namespace mozilla {
 namespace widget {
 
 class TaskbarPreviewButton;
 class TaskbarWindowPreview : public TaskbarPreview,
                              public nsITaskbarWindowPreview,
                              public nsITaskbarProgress,
+                             public nsITaskbarOverlayIconController,
                              public nsSupportsWeakReference
 {
 public:
   TaskbarWindowPreview(ITaskbarList4 *aTaskbar, nsITaskbarPreviewController *aController, HWND aHWND, nsIDocShell *aShell);
   virtual ~TaskbarWindowPreview();
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSITASKBARWINDOWPREVIEW
   NS_DECL_NSITASKBARPROGRESS
+  NS_DECL_NSITASKBAROVERLAYICONCONTROLLER
   NS_FORWARD_NSITASKBARPREVIEW(TaskbarPreview::)
 
   virtual LRESULT WndProc(UINT nMsg, WPARAM wParam, LPARAM lParam);
 private:
   virtual nsresult ShowActive(PRBool active);
   virtual HWND &PreviewWindow();
 
   virtual nsresult UpdateTaskbarProperties();
@@ -85,27 +88,32 @@ private:
   PRBool                  mHaveButtons;
   // Windows button format
   THUMBBUTTON             mThumbButtons[nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS];
   // Pointers to our button class (cached instances)
   nsWeakPtr               mWeakButtons[nsITaskbarWindowPreview::NUM_TOOLBAR_BUTTONS];
 
   // Called to update ITaskbarList4 dependent properties
   nsresult UpdateTaskbarProgress();
+  nsresult UpdateOverlayIcon();
 
   // The taskbar progress
   TBPFLAG                 mState;
   ULONGLONG               mCurrentValue;
   ULONGLONG               mMaxValue;
 
-  // WindowHook procedure for hooking mWnd for taskbar progress stuff
-  static PRBool TaskbarProgressWindowHook(void *aContext,
-                                          HWND hWnd, UINT nMsg,
-                                          WPARAM wParam, LPARAM lParam,
-                                          LRESULT *aResult);
+  // Taskbar overlay icon
+  HICON                   mOverlayIcon;
+  nsString                mIconDescription;
+
+  // WindowHook procedure for hooking mWnd for taskbar progress and icon stuff
+  static PRBool TaskbarWindowHook(void *aContext,
+                                  HWND hWnd, UINT nMsg,
+                                  WPARAM wParam, LPARAM lParam,
+                                  LRESULT *aResult);
 
   friend class TaskbarPreviewButton;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
--- a/widget/src/windows/WinTaskbar.cpp
+++ b/widget/src/windows/WinTaskbar.cpp
@@ -411,16 +411,26 @@ NS_IMETHODIMP
 WinTaskbar::GetTaskbarProgress(nsIDocShell *shell, nsITaskbarProgress **_retval) {
   nsCOMPtr<nsITaskbarWindowPreview> preview;
   nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return CallQueryInterface(preview, _retval);
 }
 
+NS_IMETHODIMP
+WinTaskbar::GetOverlayIconController(nsIDocShell *shell,
+                                     nsITaskbarOverlayIconController **_retval) {
+  nsCOMPtr<nsITaskbarWindowPreview> preview;
+  nsresult rv = GetTaskbarWindowPreview(shell, getter_AddRefs(preview));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return CallQueryInterface(preview, _retval);
+}
+
 /* nsIJumpListBuilder createJumpListBuilder(); */
 NS_IMETHODIMP
 WinTaskbar::CreateJumpListBuilder(nsIJumpListBuilder * *aJumpListBuilder) {
   nsresult rv;
 
   if (JumpListBuilder::sBuildingList)
     return NS_ERROR_ALREADY_INITIALIZED;
 
--- a/widget/src/windows/nsWindow.cpp
+++ b/widget/src/windows/nsWindow.cpp
@@ -2448,17 +2448,19 @@ NS_IMETHODIMP nsWindow::SetCursor(imgICo
   // Reject cursors greater than 128 pixels in either direction, to prevent
   // spoofing.
   // XXX ideally we should rescale. Also, we could modify the API to
   // allow trusted content to set larger cursors.
   if (width > 128 || height > 128)
     return NS_ERROR_NOT_AVAILABLE;
 
   HCURSOR cursor;
-  rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, &cursor);
+  // No scaling
+  gfxIntSize size(0, 0);
+  rv = nsWindowGfx::CreateIcon(aCursor, PR_TRUE, aHotspotX, aHotspotY, size, &cursor);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mCursor = nsCursor(-1);
   ::SetCursor(cursor);
 
   NS_IF_RELEASE(sCursorImgContainer);
   sCursorImgContainer = aCursor;
   NS_ADDREF(sCursorImgContainer);
--- a/widget/src/windows/nsWindowGfx.cpp
+++ b/widget/src/windows/nsWindowGfx.cpp
@@ -98,16 +98,28 @@ using namespace mozilla::layers;
  *
  * SECTION: nsWindow statics
  * 
  **************************************************************/
 
 static nsAutoPtr<PRUint8>  sSharedSurfaceData;
 static gfxIntSize          sSharedSurfaceSize;
 
+struct IconMetrics {
+  PRInt32 xMetric;
+  PRInt32 yMetric;
+  PRInt32 defaultSize;
+};
+
+// Corresponds 1:1 to the IconSizeType enum
+static IconMetrics sIconMetrics[] = {
+  {SM_CXSMICON, SM_CYSMICON, 16}, // small icon
+  {SM_CXICON,   SM_CYICON,   32}  // regular icon
+};
+
 /**************************************************************
  **************************************************************
  **
  ** BLOCK: nsWindowGfx impl.
  **
  ** Misc. graphics related utilities.
  **
  **************************************************************
@@ -608,34 +620,78 @@ PRBool nsWindow::OnPaint(HDC aDC, PRUint
 
   if (aNestingLevel == 0 && ::GetUpdateRect(mWnd, NULL, PR_FALSE)) {
     OnPaint(aDC, 1);
   }
 
   return result;
 }
 
+gfxIntSize nsWindowGfx::GetIconMetrics(IconSizeType aSizeType) {
+  PRInt32 width = ::GetSystemMetrics(sIconMetrics[aSizeType].xMetric);
+  PRInt32 height = ::GetSystemMetrics(sIconMetrics[aSizeType].yMetric);
+
+  if (width == 0 || height == 0) {
+    width = height = sIconMetrics[aSizeType].defaultSize;
+  }
+
+  return gfxIntSize(width, height);
+}
+
 nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer,
                                   PRBool aIsCursor,
                                   PRUint32 aHotspotX,
                                   PRUint32 aHotspotY,
+                                  gfxIntSize aScaledSize,
                                   HICON *aIcon) {
 
   // Get the image data
   nsRefPtr<gfxImageSurface> frame;
   aContainer->CopyFrame(imgIContainer::FRAME_CURRENT,
                         imgIContainer::FLAG_SYNC_DECODE,
                         getter_AddRefs(frame));
   if (!frame)
     return NS_ERROR_NOT_AVAILABLE;
 
-  PRUint8 *data = frame->Data();
-
   PRInt32 width = frame->Width();
   PRInt32 height = frame->Height();
+  if (!width || !height)
+    return NS_ERROR_FAILURE;
+
+  PRUint8 *data;
+  if ((aScaledSize.width == 0 && aScaledSize.height == 0) ||
+      (aScaledSize.width == width && aScaledSize.height == height)) {
+    // We're not scaling the image. The data is simply what's in the frame.
+    data = frame->Data();
+  }
+  else {
+    NS_ENSURE_ARG(aScaledSize.width > 0);
+    NS_ENSURE_ARG(aScaledSize.height > 0);
+    // Draw a scaled version of the image to a temporary surface
+    nsRefPtr<gfxImageSurface> dest = new gfxImageSurface(aScaledSize,
+                                                         gfxASurface::ImageFormatARGB32);
+    if (!dest)
+      return NS_ERROR_OUT_OF_MEMORY;
+
+    gfxContext ctx(dest);
+
+    // Set scaling
+    gfxFloat sw = (double) aScaledSize.width / width;
+    gfxFloat sh = (double) aScaledSize.height / height;
+    ctx.Scale(sw, sh);
+
+    // Paint a scaled image
+    ctx.SetOperator(gfxContext::OPERATOR_SOURCE);
+    ctx.SetSource(frame);
+    ctx.Paint();
+
+    data = dest->Data();
+    width = aScaledSize.width;
+    height = aScaledSize.height;
+  }
 
   HBITMAP bmp = DataToBitmap(data, width, -height, 32);
   PRUint8* a1data = Data32BitTo1Bit(data, width, height);
   if (!a1data) {
     return NS_ERROR_FAILURE;
   }
 
   HBITMAP mbmp = DataToBitmap(a1data, width, -height, 1);
--- a/widget/src/windows/nsWindowGfx.h
+++ b/widget/src/windows/nsWindowGfx.h
@@ -55,17 +55,22 @@ public:
   static nsIntRect ToIntRect(const RECT& aRect)
   {
     return nsIntRect(aRect.left, aRect.top,
                      aRect.right - aRect.left, aRect.bottom - aRect.top);
   }
 
   static nsIntRegion ConvertHRGNToRegion(HRGN aRgn);
 
-  static nsresult CreateIcon(imgIContainer *aContainer, PRBool aIsCursor, PRUint32 aHotspotX, PRUint32 aHotspotY, HICON *aIcon);
+  enum IconSizeType {
+    kSmallIcon,
+    kRegularIcon
+  };
+  static gfxIntSize GetIconMetrics(IconSizeType aSizeType);
+  static nsresult CreateIcon(imgIContainer *aContainer, PRBool aIsCursor, PRUint32 aHotspotX, PRUint32 aHotspotY, gfxIntSize aScaledSize, HICON *aIcon);
 
 private:
   /**
    * Cursor helpers
    */
   static PRUint8*         Data32BitTo1Bit(PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight);
   static PRBool           IsCursorTranslucencySupported();
   static HBITMAP          DataToBitmap(PRUint8* aImageData, PRUint32 aWidth, PRUint32 aHeight, PRUint32 aDepth);